EPOLL的LT和ET触发方式介绍
一、什么是EPOLL
linux网络编程中,很长时间用的都是select来触发事件,但是select存在如下几个缺点: 1、在Linux内核中,select所用到的FD_SET是有限的,即内核中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数,当然你可以通过修改这个宏重新编译内核来扩大数量,但是这样会带来网络性能的下降。 2、select的内核实现采用的是轮询的方式,每次都要遍历FD_SET中所有的句柄,在连接数很多的情况下,效率很低,性能难以满足要求
epoll支持的FD上限是可以打开文件的数目,这个数目和内存的大小有关系,一般1G的内存大约有10万左右,可以通过cat /proc/sys/fs/file-max查看,例如我的一台测试机就有765793,这个数目已经远远能够满足要求了。 另外在socket状态变化的事件触发处理上,epoll不会遍历所有的socket,而只对“活跃”的socket进行操作,因为内核实现中epoll是根据每个fd上的一个callback函数实现的,只有“活跃”的socket才会主动调用这个callback函数。可以说epoll实现了一个伪AIO,由os来推动。在高速LAN环境中,由于“活跃”的socket往往比较多,epoll的优势不是很明显,但是在不活跃连接较多的WAN上,epoll就能显示出极大的优势。
二、什么是EPOLL的LT和ET触发模式
LT(level triggered)也叫做水平触发,是缺省的工作方式,并且同时支持阻塞和非阻塞。在LT模式中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。原来的Transmit模块采用的也是这种LT模式。传统的select/poll都是这种模型的代表 。
ET (edge-triggered)也叫做边缘触发,是高速工作方式,只支持非阻塞socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll会通知你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是需要注意的是,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)。 ET模式的性能会优于LT模式,但是编程难度也会大一些。
LT模式是Epoll的默认设置,而设置ET模式的设置方法如下:
struct epoll_event struEvent;
struEvent.events = EPOLLIN | EPOLLOUT | EPOLLET;
struEvent.data.fd = hSocket;
epoll_ctl(m_hEpoll, EPOLL_CTL_ADD, hSocket, &struEvent);