网络编程(NIO/Netty)
2021-02-23 16:29:57 3 举报
AI智能生成
网络编程,包括NIO基础和进阶,Netty线程模型及原理(进行中)
作者其他创作
大纲/内容
重要概念
同步
处理网络IO事件时,阻塞等待IO事件完成才能做其他的
异步
将IO读写委托给OS处理,操作完成后会给我们一个通知
阻塞
当一个线程调用read()或write()方法时,直到数据被完全读取或写入,期间不能做任何事
非阻塞
如果缓冲区的数据没有准备好则直接返回,不会等待;如果数据已经准备好也直接返回
概括
<b>BIO</b>:一个连接一个线程(<b>同步阻塞IO</b>)
基于Acceptor模型实现
<b>NIO</b>:一个请求一个线程(<b>同步非阻塞IO</b>)
基于Reactor模型实现
<b>AIO</b>:一个有效请求一个线程(<b>异步非阻塞IO</b>)
基于Proactor模型实现
NIO基础 👉
NIO进阶
源码解析
Selector.open();
底层实现取决于JDK版本
Windows:WindowsSelectorProvider<br>MacOS:KQueueSelectorProvider<br>
Linux
SunOS:DevPollSelectorProvider<br><b>Linux:EPollSelectorProvider</b><br>Other:PollSelectorProvider<br>
<font color="#000000"><b>一句话概括:在linux系统中创建 epoll 实例</b></font><br><br><br><br><br><font color="#16884a">SelectorProvider.provider()</font><font color="#662c90">.openSelector()<br><br><br><br><br><br></font>
1、创建Selector对象并调用openSelector()方法:<br> DefaultSelectorProvider.create() 根据不同版本jdk返回<br><font color="#00a650"> EPollSelectorProvider() </font><font color="#5c5c5c">--<b style="">linux系统下的实现是epoll</b></font><br> 所以源码等同于:<font color="#662c90">EPollSelectorProvider.openSelector()<br></font>2、EPollSelectorProvider.java 中 return new EpollSelectorImpl(this)<br>3、<b>EpollSelectorImpl.java</b> 的构造方法中有 new EpollArrayWrapper()<br>4、EpollArrayWrapper.java 在初始化调用构造方法时有 epfd = epollCreate()<br>5、epollCreate()是native方法,在openjdk中通过类名_本地方法名就能找到c代码<br>6、c代码写的本地方法中调用linux内核函数epoll_create(256) 创建epoll实例并返回
ssc.register(selector, SelectionKey.OP_ACCEPT)
底层调用的 <b>pollWrapper.add(fd)</b>
<b><font color="#000000">将 连接 添加到 Selector 内部集合中</font></b>
selector.select()
底层调用的 EpollSelectorImpl.java 中的 <b>pollWrapper.poll(timeout)</b>
updateRegistrations()<br><b>这才是真正的事件注册</b>
<font color="#000000"><b>监听连接集合中是否有事件发生,如果有则将事件放入事件集合中</b></font>
原理
底层调用native方法 epollCtl()
<b>epoll_ctl()</b>
调用native方法 epollWait()
<b><font color="#000000">阻塞等待事件集合中是否有事件,如果有则遍历事件处理</font></b>
底层调用 linux 内核函数
epoll_wait()
epoll函数
int <b>epoll_create</b>()
创建一个 epoll 实例,并返回一个非负数作为文件描述符
int <b>epoll_ctl</b>(int epfd, int op, int fd, events)
使用文件描述符 epfd 引用的 epoll 实例,对目标文件描述符 fd 执行 op 操作
参数 op 有以下选项
EPOLL_CTL_ADD:注册新的 fd 到 epfd 中,并关联事件 event<br>EPOLL_CTL_MOD:修改已经注册的 d 的监听事件<br> EPOLL_CTL_DEL:从 epfd 中移除 fd,并且忽略掉绑定的 event,这时 event 可以为 null
events 有以下可选值
EPOLLIN:表示对应的文件描述符是可读的;<br>EPOLLOUT:表示对应的文件描述符是可写的;<br>EPOLLERR:表示对应的文件描述符发生了错误;<br>成功则返回 0,失败返回 -1
int <b>epollWait</b>(epfd, events, numfds, timeout)
监听感兴趣的事件集合是否有事件产生<br>
epfd 是 epoll 对应的文件描述符,events 表示调用者所有可用事件的集合,<br>maxevents 表示最多等到多少个事件就返回,timeout 是超时时间
多路复用
IO多路复用
在一个操作里同时监听多个输入输出源,在其中一个或多个输入输出源可用的时候返回,然后对其的进行读写操作
优点:单个进程可以同时处理多个网络连接的 I/O
多路复用器
<b>select</b><br>windows
监听 fd(文件描述符),集合大时效率低,限制最大连接数为 1024,时间复杂度 O(n)
它仅仅知道,有I/O事件发生了,并不知道具体哪个流,所以需要我们遍历整个集合
缺点
连接数受限(1024)
查找匹配速度慢,轮询整个集合
数据由内核态拷贝到用户态
poll()<br>other
poll 本质上和 select 没有区别,也需要内存拷贝和遍历 fd 集合,时间复杂度 O(n)<br>
优点
没有最大连接数的限制,因为它是基于链表来存储的
<b>epoll</b><br>linux
epoll 全称 eventpoll,是 linux 内核实现IO多路复用的方式,时间复杂度 O(1)
特点
共享内存
epoll有一块特殊的内存,这块内存是应用程序和内核共享的
事件通知
在内存中所有要添加监听的套接字,不是轮询,而是通知
优点
没有最大并发连接数的限制
通过事件回调机制只处理有事件的 fd
通过用户和内核的公用空间让epoll减少了复制的过程
区别
select/epoll 只有一个系统调用,每次要监听都要将其从用户态拷贝到内核,有事件时返回整个集合
epoll 监听的 fd 集合是常驻内核的,它有 3 个系统调用 (epoll_create, epoll_wait, epoll_ctl)通过 epoll_wait 可以<br>多次监听同一个 fd 集合,只返回可读写那部分
epoll 的性能并不一定比 select/poll 高,对于连接数量较少并且I/O都非常繁忙的情况下,select/poll 在性能上有优势,<br>毕竟 epoll 的通知机制需要很多函数回凋
epoll相较于select和poll机制来说,其高效的原因是将基于事件的fd放到内核中来完成,在内核中基于红黑树+链表数据<br>结构来实现,链表存放有事件发生的fd集合,然后在调用epoll_wait时返回给应用程序,由应用程序来处理这些fd事件
Netty
点击跳转 👉
0 条评论
下一页