i/o复用:select、poll、epoll
其中,epoll是Linus特有的i/o复用函数,在实现与使用上与select、poll有很大的差异。
epoll:
每轮循环:都要从用户空间往内核空间拷数据
内核轮询:检测每个描述符有没有就绪 O(n)
io函数返回后,遍历每个描述符,找到有事件就绪的描述符 O(n)
epoll_create() :创建内核事件表 红黑树
epoll_ctl(): 向内核事件表 添加、删除、修改
epoll_weit(): 只返回有就绪事件的描述符
LT模式:描述符事件就绪后,如果用户没有处理完数据,epoll会继续提醒,直到处理完
ET模式(高效模式):描述符上事件就绪后,无论用户有没有处理完数据,epoll只会处理一次 EPOLL|N|
添加头文件#include<fcntl.h>
fcntl(fd,F_GETFL);
oldflg|O_NONBLOCK
(ET模式必须使用描述符非堵塞模式)
poll:循环遍历得到就绪描述符 O(n)
epoll:有内核事件表,描述符直接+1 O(1)
适用于 描述符多,就绪事件少
select:适用于 描述符少,就绪事件多的情况 O(n)
epoll与select和poll相比的优缺点:
1、select、poll
每次循环都需要从用户空间向内核空间传递数据
epoll
直接在内核空间创建事件表,每个描述符只需要传递一次
2、select、poll
在内核中以轮询的方式检测有就绪事件的描述符 O(n)
epoll
在每个描述符上注册回调函数,事件就绪后,执行回调函数,描述符添加到就绪队 O(n)
3、select、poll
返回后,需要遍历所有文件描述符,才能找到就绪的 O(n)
epoll
直接找到就绪描述符,不需要遍历所有描述符 O(1)
代码如下