当FD有数据可读时,我们调用epoll_wait就可以得到通知。但是事件通知的模式有两种:
举个栗子:
LT的问题
由于重复通知其效率会受影响
LT可能会出现惊群现象,当一个fd就绪通知完成后他这个fd信息还会存在list_head链表中这也就导致所有监听这个fd的进程最后都会被通知到,也就是说一个fd就绪所有监听线程都会被唤醒,ET就不会有这个现象它通知完就直接移除了不会保留fd
ET的问题
当有多个fd就绪通知服务端调用epoll_wait,由于ET只通知一次而数据量超过服务端数据读取上限没有一次读取完,再次读取时剩余的fd已经被移除掉了,造成残留数据问题
残留数据问题解决方案
方案一:
在第一次读完list_head中的fd数据后如果还有数据的情况下再手动的把原有的fd添加回list_head中,添加方式调用epoll_ctl方法(epoll_ctl的作用对eventpoll的fd实例进行增删改查)修改fd状态为就绪,当程序去做修改时eventpoll会检查是否有fd就绪,这样就会把就绪的fd添加到list_head中
方案二:
在ET读取list_head中数据时用循环一次性读完,注意这里不能用阻塞IO去读取会造成死循环,读取不到直接返回相应结果
ET模式避免了LT模式可能出现的惊群现象
ET模式最好结合非阻塞IO读取FD数据,相比LT会复杂一些
基于epoll模式的web服务的基本流程如图
评论