手写Netty之多路复用Select小案例
注意:本文只是将上文多路复用器Select、Poll、Epoll区别梳理中提出的概念与Netty中的步骤联系起来,方便后面回顾,代码中注释很多,对于大家来说如果不是怀有同样的目的,不一定有用。
单线程调度Select模拟实现,后面处理多个连接是采用的轮询,也就睡一直while循环遍历:
public class SocketMultiplexingSingleThreadv1 {
private ServerSocketChannel server = null;
/*
Selector相当于linux中的多路复用器(select poll epoll kqueue) nginx event{}
* */
private Selector selector = null;
int port = 9090;
/*初始化服务方法*/
public void initServer() {
try {
server = ServerSocketChannel.open();
server.configureBlocking(false);
server.bind(new InetSocketAddress(port));
/*
如果在epoll模型下,open这一步相当于是执行了epoll_create方法,
kernel在内存上开辟红黑树空间,产生一个文件描述符fd3,
另外select poll epoll三种多路复用选择器优先选择:epoll,可以用-D修正
*/
selector = Selector.open();
/*
server 约等于 listen状态的 fd4,后面fd4负责accept,要将fd4注册到fd3上,
若有多个时间,可以将多个fd注册到fd3上,最后将fd3返回。
server.register(),这一步相当于调用epoll的epoll_ctl(fd3,add,fd4),
fd3是返回值,fd4是事件,add是操作
如果:
select,poll:jvm里开辟一个数组fd4放进去
epoll: epoll_ctl(fd3,ADD,fd4,EPOLLIN
*/
server.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
/*启动之后调用这个方法*/
public void start() {
//初始化服务端,包括绑定端口、设置非阻塞,注册到多路复用器上
initServer();
System.out.println("服务器启动了。。。。。");
//然后开始轮询,一直循环
try {
while (true) {
//返回选择器里面的key.打印着玩玩,没啥用
Set<SelectionKey> keys = selector.keys();
System.out.println(keys.size()+" size");
/*1,调用多路复用器(select,poll or epoll (epoll_wait))
下面selector.select()的意思:
1,如果是select,poll复用器,那么内核执行的是select(fd4)或者poll(fd4)
2,如果是epoll复用器,执行的是内核的 epoll_wait()方法,会返回一个链表,这儿是返回有效连接个数
*, 参数可以带时间:没有时间,0 : 阻塞,有时间设置一个超时
selector.wakeup() 结果返回0
懒加载:
其实在触碰到selector.select()调用的时候触发了epoll_ctl的调用
*/
while (selector.select() > 0) {
//返回的selectionKeys是有状态的fd集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//对fd几何进行遍历
Iterator<SelectionKey> iter = selectionKeys.iterator();
/*
不管使用的是什么多路复用器,都只是给服务器状态集,还是需要服务器去一个一个的处理他们的R/W。同步好辛苦!
区别是:
NIO自己对着每一个fd调用系统调用,这中间设计状态切换,非常浪费资源,
而Epoll只需要一次调用,内核kernel已经将状态统计好,返回给服务端,服务端根据状态精准的读取,避免无效的轮询
*/
while (iter.hasNext()) {
//拿到返回的状态集合进行遍历,key抓住当前事件,同时将事件从原集合中移除,避免重复处理
SelectionKey key = iter.next();
iter.remove(); //set 不移除会重复循环处理
if (key.isAcceptable()) {
/*
看代码的时候,这里是重点,如果要去接受一个新的连接
语义上,accept接受连接且返回新连接的FD对吧?
那新的FD怎么办?
select,poll,因为他们内核没有空间,那么在jvm中保存和前边的fd4那个listen的一起
epoll: 我们希望通过epoll_ctl把新的客户端fd注册到内核空间
*/
acceptHandler(key);
} else if (key.isReadable()) {
readHandler(key);
/*
连read 还有 write都处理了
在当前线程,这个方法可能会阻塞 ,如果阻塞了十年,其他的IO早就没电了。。。
所以,为什么提出了 IO THREADS
redis 是不是用了epoll,redis是不是有个io threads的概念 ,redis是不是单线程的
tomcat 8,9 异步的处理方式 IO 和 处理上 解耦
*/
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void acceptHandler(SelectionKey key) {
try {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
//来啦,目的是调用accept接受客户端,连接文件描述符fd7
SocketChannel client = ssc.accept();
//设置非阻塞
client.configureBlocking(false);
//buffer作用是缓冲,数据就不一个个读,而是一块块读
ByteBuffer buffer = ByteBuffer.allocate(8192);
/*
调用了register,与之前类似,分select(poll)、Epoll两种情况
select,poll:jvm里开辟一个数组 fd7 放进去
epoll: epoll_ctl(fd3,ADD,fd7,EPOLLIN
fd3是内核开辟的空间哦~,将fd7放进去
*/
client.register(selector, SelectionKey.OP_READ, buffer);
System.out.println("-------------------------------------------");
System.out.println("新客户端:" + client.getRemoteAddress());
System.out.println("-------------------------------------------");
} catch (IOException e) {
e.printStackTrace();
}
}
/*读事件处理*/
public void readHandler(SelectionKey key) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
buffer.clear();
int read = 0;
try {
while (true) {
read = client.read(buffer);
if (read > 0) {
buffer.flip();
while (buffer.hasRemaining()) {
client.write(buffer);
}
buffer.clear();
} else if (read == 0) {
break;
} else {
client.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SocketMultiplexingSingleThreadv1 service = new SocketMultiplexingSingleThreadv1();
service.start();
}
}
手写Netty之多路复用Select小案例的更多相关文章
- servlet(1) - 手写第一个servlet程序 - 小易Java笔记
声明:如tomcat的安装目录为D:\Java\tomcat6,下面要根据tomcat的安装目录而定 1. 建立程序的文件结构 ==>找到tomcat的安装目录,在webapps目录下新建一个名 ...
- 纯css手写圆角气泡对话框 微信小程序和web都适用
嗯……我们设计师强烈要求一定要圆角!圆角的气泡对话框,不要那种尖角的.这其中还遇上了个尴尬的问题,z-index不生效 无非就是两种方法,一种是使用图片再定位拼接起来使用,太简单了具体就不详细的说了. ...
- Python:通过一个小案例深入理解IO多路复用
通过一个小案例深入理解IO多路复用 假如我们现在有这样一个普通的需求,写一个简单的爬虫来爬取校花网的主页 import requests import time start = time.time() ...
- 初学源码之——银行案例手写IOC和AOP
手写实现lOC和AOP 上一部分我们理解了loC和AOP思想,我们先不考虑Spring是如何实现这两个思想的,此处准备了一个『银行转账」的案例,请分析该案例在代码层次有什么问题?分析之后使用我们已有知 ...
- [年薪60W分水岭]基于Netty手写Apache Dubbo(带注册中心和注解)
阅读这篇文章之前,建议先阅读和这篇文章关联的内容. 1. 详细剖析分布式微服务架构下网络通信的底层实现原理(图解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...
- 一个ssm综合小案例-商品订单管理----写在前面
学习了这么久,一直都是零零散散的,没有把知识串联起来综合运用一番 比如拦截器,全局异常处理,json 交互,RESTful 等,这些常见技术必须要掌握 接下来呢,我就打算通过这么一个综合案例把这段时间 ...
- 一个常见下拉菜单的样式:一体化小三角(纯css手写解决)
类似下拉菜单2个一体化小三角,习惯上用字体图标加jQuery处理,比较方便,但是下面纯css手写解决方式,效果也还不错,对CSS知识也是一个比较好的孔固. 小三角用了2种不同处理方式:1.利用bord ...
- 全网最详细最好懂 PyTorch CNN案例分析 识别手写数字
先来看一下这是什么任务.就是给你手写数组的图片,然后识别这是什么数字: dataset 首先先来看PyTorch的dataset类: 我已经在从零学习pytorch 第2课 Dataset类讲解了什么 ...
- 手写一个类SpringBoot的HTTP框架:几十行代码基于Netty搭建一个 HTTP Server
本文已经收录进 : https://github.com/Snailclimb/netty-practical-tutorial (Netty 从入门到实战:手写 HTTP Server+RPC 框架 ...
随机推荐
- 浅析Python装饰器
1.什么是装饰器 在介绍装饰器之前,我们先来思考一个问题:使用Python语言进行程序设计时,如果我们想扩展一个函数的功能,一般会怎么做呢? 比如,有一个名为print_info函数,当前该函数内只做 ...
- 这是一篇SQL注入文章
目录 注入原理: 1.寻找注入点的方式或注入的地方可能包括. 2.注入点判断方法. 3.注入分类. 数字型: 字符型: 搜索型: XX型(也叫其他型): 4.注入提交方式. 5.注入攻击类型与方式. ...
- RocketMQ(十):数据存储模型设计与实现
消息中间件,说是一个通信组件也没有错,因为它的本职工作是做消息的传递.然而要做到高效的消息传递,很重要的一点是数据结构,数据结构设计的好坏,一定程度上决定了该消息组件的性能以及能力上限. 1. 消息中 ...
- 元旦在家撸了两天Seata源码,你们是咋度过的呢?
撸Seata源码 2020年12月31日晚23点30分,我发了2020年的最后一个朋友圈:假期吃透Seata源码,有组队的吗? 不少小伙伴都来点赞了, 其中也包括Seata项目的发起人--季敏大佬哦! ...
- Eclipse 使用svn时出现 “Previous operation has not finished; run 'cleanup' if it was interrupted“问题
在执行svn操作的时候出现了下面的问题 commit -m "" E:/eclipse/workplace/BRobotAPP/blockly/googleDemo/blockly ...
- Typecho 主题更换
Typecho 主题更换 前言 上一篇已经搭建自己的 Typecho 博客,博客搭建完成自带一个默认主题,不是很喜欢默认的主题,想换一个自己喜欢的主题,并在基础上进行修改. 本文就介绍下如何更换和自定 ...
- Redis-基础和应用篇
2020,到新公司这一年多以来,更新文章和总结知识的习惯被丢掉了.我复盘了下自己,原因不是公司技术氛围不好,也不是每天业务需求太多,其根本原因还是---惰性.作为我们技术人随着年龄的增长,精力也会被生 ...
- Android-SDK接入-YSDK(应用宝1.7.0)
SDK接入-YSDK(应用宝1.7.0)-2021-01-07 大家好,近期在多渠道打包平台,会定期遇到第三方SDK升级,所以很被动的是,我们也要跟随他们的步伐,及时升级.否则将面临第三方开发者站无法 ...
- 在php里做js操作
'echo <script>js_operation</script>';
- 【原创】Linux PCI驱动框架分析(三)
背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...