文章目录
-
-
-
- 概述
- select
- poll
-
- poll比select的优势
- epoll
-
- ET/LT模式
- epoll和select、poll的区别
- 参考
-
-
概述
IO多路复用即一个函数(函数集)跟多个套接字进行IO操作,常见类型为select、poll、epoll
select
int select(int maxfdp1, fd_set* readset, fd_set* writeset, fd_set* exceptset, const struct timeval* timeout);
检查从0到maxfdp1-1的描述符,检测到可读、可写、异常的描述符会放到各自的链表中,timeout设置阻塞超时时间。
poll
int poll(struct pollfd* fdarray, unsigned long nfds, int timeout);
struct pollfd {
int fd; // 检查的文件描述符
short events; // 要测试的条件
short revents; // 返回时对该描述符的状态
}
fdarray里面放想要检测的文件描述符
poll比select的优势
- 将不同类型的事件放到同一个链表,再统一处理,接口简单
- poll在链表上挂的是感兴趣的文件描述符,而select是无差别轮询
epoll
epoll是一个类型,由epoll_create、epoll_ctl、epoll_wait三个函数构成。
- epoll_create初始化一个文件描述符,里面包含了两个数据结构,红黑树和双向链表。其中,红黑树上装的是用户感兴趣的事件,双向链表装的是就绪的事件。
int epollfd = epoll_create(5);
- epoll_ctl往红黑树添加、修改、删除用户感兴趣的事件。在往红黑树添加事件的同时,向内核注册一个该事件对应的回调函数。在事件就绪时,内核通过回调函数将该事件添加到双向链表。
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
- epoll_wait将双向链表上的就绪事件复制到用户空间
int number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
ET/LT模式
-
LT模式,水平触发
LT模式在epoll_wait函数内将就绪事件链表清空,然后创建备份链表,设置为LT模式的事件会放到该链表中(不管是否处理完成),函数结束后,该链表成为新的就绪事件链表。对于处理完成的事件,下次调用的时候返回NULL,内核会将其清除。
-
ET模式,边缘触发
对与设置为ET模式的事件不会放到新的链表中,即只触发一次,高效。
epoll和select、poll的区别
- 时间复杂度:epoll在拿就绪事件是O(1),select和poll为O(1)
- 资源消耗:epoll利用多一个文件描述符记录感兴趣事件和就绪事件,并且每个事件都调用了回调函数。select和poll较简单
- 使用:监听事件多,实际发生事件少时用epoll。实际发生事件多时用poll,避免大量回调函数。
参考
- https://blog.csdn.net/tianjing0805/article/details/76021440
- https://www.cnblogs.com/gaorong/p/7496993.html
- 《Linux高性能服务器编程》游双