epoll联机帮助页说,如果未完成读取,则向EPOLLET(边缘触发)注册的fd不应通知两次EPOLLIN。
因此,在EPOLLIN之后,您需要先清空缓冲区,然后epoll_wait才能针对新数据返回新的EPOLLIN。
但是,我遇到这种方法的问题,因为我看到了未修改fds的重复EPOLLIN事件。
这是strace的输出,0x200是EPOLLRDHUP,尚未在我的glibc header 中定义,但在内核中定义。
30285 epoll_ctl(3, EPOLL_CTL_ADD, 9, {EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET|0x2000, {u32=9, u64=9}}) = 0
30285 epoll_wait(3, {{EPOLLIN, {u32=9, u64=9}}}, 10, -1) = 1
30285 epoll_wait(3, {{EPOLLIN, {u32=9, u64=9}}}, 10, -1) = 1
30285 epoll_wait(3, <unfinished ...>
30349 epoll_ctl(3, EPOLL_CTL_DEL, 9, NULL) = 0
30306 recv(9, "7u\0\0\10\345\241\312\t\20\f\32\r\10\27\20\2\30\200\10 \31(C0\17\32\r\10\27\20\2\30"..., 20000, 0) = 20000
30349 epoll_ctl(3, EPOLL_CTL_DEL, 9, NULL) = -1 ENOENT (No such file or directory)
30305 recv(9, " \31(C0\17\32\r\10\27\20\2\30\200\10 \31(C0\17\32\r\10\27\20\2\30\200\10 \31("..., 20000, 0) = 10011
因此,在将fd数加9之后,在收到文件描述符之前,我确实收到了2个连续的EPOLLIN事件,系统调用跟踪显示了如何在读取前删除fd,但该事件应该仅发生一次,每个事件一次。
因此,要么我没有正确阅读联机帮助页,要么现在有些东西在起作用。
最佳答案
我认为您错过了epoll
手册页的这一部分:
那就是:在第一个read()
发生之前,您有两个数据块到达接收队列,这意味着您有两个epoll事件。似乎EPOLLONESHOT
是您要使用的,当事件发生时,它将从轮询集中原子地删除文件描述符(因此您无需执行EPOLL_CTL_DEL
)。