【知识积累】深入Hotspot源码理解NIO多路复用器

本文源码:https://github.com/axin1240101543/netty(有什么问题可以提issue给我,一起学习,共同进步。)

一、流程图

NIO源码

二、源码狙击 - Selector.open()

调用openSelector方法,返回一个EpollSelectorImpl的实现

实现了一个数组用来存放fd

创建epoll文件描述符

调用native方法

C语言实现的调用Linux内核的函数epoll_create

三、源码狙击 - serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

将fd(socketChannel)添加到数组中

四、源码狙击 - selector.select();

调用native方法

C语言实现的调用Linux内核的函数epoll_ctl

调用native方法

C语言实现的调用Linux内核的函数epoll_wait

五、Epoll内核函数解析

1、epoll_create

int epoll_create(int size);

创建一个epoll实例,并返回一个非负数作为文件描述符,用于对epoll接口的所有后续调用。参数size代表可能会容纳size个描述符,但size不是一个最大值,只是提示操作系统它的数量级,现在这个参数基本上已经弃用了。

2、epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event  *event);

使用文件描述符epfd引用的epoll实例,对目标文件描述符fd执行op操作。
参数epfd表示epoll对应的文件描述符,参数fd表示socket对应的文件描述符。
参数op有以下几个值:
EPOLL_CTL_ADD:注册新的fd到epfd中,并关联事件event;
EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
EPOLL_CTL_DEL:从epfd中移除fd,并且忽略掉绑定的event,这时event可以为null;
参数event是一个结构体

1 struct epoll_event {
2  __uint32_t events; /* Epoll events */
3  epoll_data_t data; /* User data variable */
4  };
5
6  typedef union epoll_data {
7  void  *ptr;
8  int fd;
9  __uint32_t u32;
10  __uint64_t u64;
11  } epoll_data_t;

events有很多可选值,这里只举例最常见的几个:
EPOLLIN :表示对应的文件描述符是可读的;
EPOLLOUT:表示对应的文件描述符是可写的;
EPOLLERR:表示对应的文件描述符发生了错误;
成功则返回0,失败返回-1

3、epoll_wait

int epoll_wait(int epfd, struct epoll_event  *events, int maxevents, int timeout);

等待文件描述符epfd上的事件。
epfd是Epoll对应的文件描述符,events表示调用者所有可用事件的集合,maxevents表示最多等到多少个事件就返回,
timeout是超时时间。

六、小结

I/O多路复用底层主要用的Linux 内核函数(select,poll,epoll)来实现,windows不支持epoll实现,windows底层是基于winsock2的
select函数实现的(不开源)

  select(jdk1.4) poll epoll(jdk1.5及以上)
操作方式 遍历 遍历 回调
底层实现 数组 链表 哈希表
IO效率 每次调用都进行线性遍历,时间复杂度为O(N) 每次调用都进行线性遍历,时间复杂度为O(N) 事件通知方式,每当有IO事件就绪,系统注册的回调函数就会被调用,事件复杂度O(1)
最大连接 有上限 1024 无上限 无上限

猜你喜欢

转载自blog.csdn.net/axin1240101543/article/details/117232534