参考博客,这一篇是我目前看到写得最好的一篇:LT模式和ET模式
描述下流程:
一颗红黑树,有个epollfd,先创建listenfd监听一些事件并加到epollfd上,如果有事件到来,创建connfd,监听一些事件并加到epollfd,epoll_wait是用的epollfd,然后for处理这些触发的事件:
if fd==listenfd{
}else if fd =connfd{
}
epoll默认lt,可et。
lt:
若缓冲区中有10k数据,可以多次进行读取。
- 比如先读取2k数据,再次调用epoll_wait(),并且会立刻通知socket读事件就绪,可以再次读取剩余的数据。
et:
若缓冲区中有10k数据,第一次只读取了1k。
- 再次调用epoll_wait,已经不是就绪状态了,因此一定要一次性的把socket上的数据收取干净(也就是说,一定要循环调用recv函数直到recv出错)。
- ET模式下,只有当缓冲区中数据由无到有,由少变多时(如果上一次触发后未将socket上的数据读完,也不会再触发,除非再新来一次数据)才会进行读取数据,对于写(除非TCP窗口由不饱和变成饱和再一次变成不饱和,才会再次触发EPOLLOUT事件)。
由于使用了使用了ET模式,所以只会触发一次POLLIN事件,如果此时没有新数据到来,就再也不会触发。所以,如果我们继续向服务器发送一条新数据加123,则服务器将再次触发一次EPOLLIN事件,然后打印出字母b。
对于写事件,如果是lt,若有可写就会会一直触发,当使用ET模式下,即使服务端给客户端fd注册了检测可写事件,可写事件也不会一直触发,只会触发一次,触发完成后只有再次注册,检测可写事件时,可写事件才会继续触发。
在LT模式下,不需要写事件时一定要及时移除,避免不必要地触发且浪费CPU资源;在ET模式下,写事件触发后,如果还需要下一次的写事件触发来驱动任务(例如,发送上次剩余的数据),则我们需要继续注册一次检测可写事件。
LT模式和ET模式各有优缺点。使用LT模式时,我们可以自由决定每次读取多少字节(对于普通socket)或何时接收连接(对于监听socket),但是可能会导致多次触发;使用ET模式,我们必须每次都将数据收完,或立即调用accept接收连接(对于监听socket),其优点是触发次数少。