epoll在epollet模式下返回2个epollin,然后从插座阅读
-
28-09-2019 - |
题
Epoll Manpage说,如果未完成阅读,则在Epollet(Edge触发)注册的FD不应两次通知Epollin。
因此,在Epollin之后,您需要在Epoll_Wait能够在新数据上返回新的Epollin之前清空缓冲区。
但是,我正在遇到这种方法问题,因为我看到了重复的Epollin事件,可用于未受感染的FD。
这是strace输出,0x200是epollrdhup,在我的glibc标题中尚未定义,但在内核中定义。
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事件,Syscall Trace显示了我在阅读之前的删除FD的方式,但每次事件只能发生一次。
因此,我要么不正确阅读该手册,要么现在在这里工作。
解决方案
我想你错过了这一部分 epoll
男人页:
由于在收到多个数据时也可以生成边缘触发的EPOLL多个事件,但呼叫者可以选择指定该数据
EPOLLONESHOT
标志,告诉epoll接收到事件后,禁用关联的文件描述符epoll_wait(2)
. 。当。。。的时候EPOLLONESHOT
指定标志,使用呼叫者有责任使用文件描述符。epoll_ctl(2)
和EPOLL_CTL_MOD
.
也就是说:您在第一次之前有两个数据到达接收队列 read()
发生了,这意味着您有两个Epoll事件。这好像是 EPOLLONESHOT
是您所追求的,当事件发生时,它会从原子上删除文件描述符(因此您无需执行 EPOLL_CTL_DEL
).
其他提示
Edge Trigger只是指(除非您使用过Epolloneshot),当某些东西进入(内核)缓冲区时,您将获得1个事件。
因此,如果您获得了1个Epollin事件,并且对此一无所获,那么下次有些数据到达该描述符时,您将获得另一个epollin - 如果没有新的数据到达,即使您没有获得事件,即使您没有进行事件读取第一个事件所示的任何数据。
好吧,简洁地说,epolloneshot只是意味着,如果您不阅读应该阅读的数据,它们将被丢弃。
通常,如果您不读取相同的数据,就会通知您的事件。但是,使用epolloneshot,不阅读数据是完全合法的,他们将被忽略。因此,不会生成其他事件。