IO多路复用
什么是IO多路复用,假设有1000个文件或者网络IO需要我们处理,这里统称为IO,无论IO是否阻塞,总需要有线程去等待IO的完成,那么难道有1000个IO,就要去开1000个线程去监听吗,这样做资源浪费太过严重,所以不同的系统提供了不同的IO多路复用(select,poll,epoll)
I/O 多路复用被用来处理同一个事件循环中的多个 I/O 事件。I/O 多路复用需要使用特定的系统调用,最常见的系统调用是 epoll
epoll
将检测文件描述符的变化委托给内核去处理, 然后内核将发生变化的文件描述符对应的事件返回给应用程序
epoll的底层是红黑树
函数介绍:
int epoll_create(int size)
函数说明: 创建一个树根
参数说明:
- size: 最大节点数, 此参数在linux 2.6.8已被忽略, 但必须传递一个大于0的数
返回值:
- 成功: 返回一个大于0的文件描述符, 代表整个树的树根
- 失败: 返回-1, 并设置errno值
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
函数说明: 将要监听的节点在epoll树上添加, 删除和修改
参数说明:
- epfd: epoll树根
- op:
EPOLL_CTL_ADD: 添加事件节点到树上
EPOLL_CTL_DEL: 从树上删除事件节点
EPOLL_CTL_MOD: 修改树上对应的事件节点
- fd: 事件节点对应的文件描述符
- event: 要操作的事件节点
struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ }; typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t;
event.events常用的有:
- EPOLLIN: 读事件
- EPOLLOUT: 写事件
- EPOLLERR: 错误事件
- EPOLLET: 边缘触发模式
event.fd: 要监控的事件对应的文件描述符
epoll的两种模式ET和LT模式
- 水平触发: 只要缓冲区中有数据, 就一直通知
- 边缘触发: 缓冲区中有数据只会通知一次, 之后再有数据才会通知(若是读数据的时候没有读完, 则剩余的数据不会再通知, 直到有新的数据到来),边缘非阻塞模式: 提高效率
select
多路IO技术: select, 同时监听多个文件描述符, 将监控的操作交给内核去处理,
数据类型
int select(int nfds, fd_set * readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
函数介绍: 委托内核监控该文件描述符对应的读,写或者错误事件的发生
参数说明:
- fd_set: 文件描述符集合
- nfds: 最大的文件描述符+1
- readfds: 读集合, 是一个传入传出参数
传入: 指的是告诉内核哪些文件描述符需要监控
传出: 指的是内核告诉应用程序哪些文件描述符发生了变化
- writefds: 写文件描述符集合(传入传出参数)
- execptfds: 异常文件描述符集合(传入传出参数)
- timeout:
NULL–表示永久阻塞, 直到有事件发生
0 --表示不阻塞, 立刻返回, 不管是否有监控的事件发生
>0–到指定事件或者有事件发生了就返回
返回值:
- 成功返回发生变化的文件描述符的个数
- 失败返回-1, 并设置error值
select优点:
- 一个进程可以支持多个客户端
- select支持跨平台
select缺点:
- 代码编写困难
- 会涉及到用户区到内核区的来回拷贝
- 当客户端多个连接, 但少数活跃的情况, select效率较低
例如: 作为极端的一种情况, 3-1023文件描述符全部打开, 但是只有1023有发送数据, select就显得效率低下 - 最大支持1024个客户端连接,select最大支持1024个客户端连接不是有文件描述符表最多可以支持1024个文件描述符限制的, 而是由FD_SETSIZE=1024限制的。FD_SETSIZE=1024 fd_set使用了该宏, 当然可以修改内核, 然后再重新编译内核, 一般不建议这么做。
epoll,poll,select总结
select:能够监听的文件描述符最多1024个,实际生产中往往不够用,并且有事件触发了要轮询所有的IO事件,效率低下
poll:本质上和select没什么区别,只是突破了1024这个限制
epoll:没有最大并发连接的限制,而且效率提升,不是轮询的方式,只有有事件发生的event才会返回