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