select、poll、epoll

select的话,首先会将socket连接创建的文件描述符(是一个数字)放入fds数组中,然后会用bitmap(rset)来表示哪一个文件描述符被创建了,而bitmap的大小是1024,所以单个进程所打开的FD是有一定限制的,它由FD_SETSIZE设置,默认值是1024。然后用户态会将这个rset拷贝给内核。内核会监听rset中的文件描述符,如果没有一直没有数据即描述符就绪时就一直阻塞,直到有描述符就绪时返回,并且有数据的那个描述符会在rset中被置位,相当于插个旗子说明这个描述符有数据,然后select返回,通过遍历rset来找到就绪的描述符。缺点:最大1024,rset不可重用,拷贝rset需要开销,O(n)复杂度遍历找到就绪的描述符。
poll:poll执行过程和select一样,但基于结构体存储fd没有采用bitmap     pollfds
struct pollfd{
int fd;
short events;//在意的事件,比如pollin pollout
short revents; //事件的反馈,可重用
}
同样会置位,但他置位的是revents,然后遍历pollfds数组判断revents有没有被置位,置位了则说明有事件就绪了,则进行处理,但revents是可以复用的,因为他会在被处理后重新置为0的。所以poll解决了1024大小的限制以及pollfd是可以重用的。
epoll:调用epoll_create()建立一个epoll对象,调用epoll_ctl向epoll对象中添加注册新的描述符或者是改变某个文件描述符的状态,调用epoll_wait收集发生的事件的连接,他依靠每个fd的callback回调函数来实现只关心就绪描述符的功能,只有准备就绪的描述符才会调用回调函数。这样IO效率 不会随着 FD 数目的增加而线性下降;epoll_wait是有返回值的,返回的就是一共多少个fd就绪了,这是因为他会把就绪的fd重排,在events数组中往前移动。因此他没有1024大小限制问题,也没有O(n)复杂度遍历找到就绪的描述符的问题。IO效率 不会随着 FD 数目的增加而线性下降;
epoll对文件描述符的操作有两种模式:LT(level trigger)和ET(edge trigger)。LT模式是默认模式,LT模式与ET模式的区别如下:
LT模式(水平触发):当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件。
ET模式(边缘触发):当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。

原文地址:https://www.cnblogs.com/wl889490/p/13402378.html