2013-01-08 31 views
1

我在看到epoll_wait()和侦听器套接字之间的以下交互。创建监听套接字事件的顺序是:epoll_wait()在侦听器套接字和虚假故障

  1. 呼叫socket()
  2. 呼叫bind()
  3. 电话fcntl(),并设置为无阻塞
  4. 呼叫epoll_ctl()EPOLL_CTL_ADDEPOLLET | EPOLLONESHOT | EPOLLIN
  5. 通话listen()

后台线程调用epoll_wait()这个套接字和其他的,如果在步骤4和5之间碰巧这样做,然后收到一个EPOLLHUP事件监听套接字事件。改变序列:

  1. 呼叫socket()
  2. 呼叫bind()
  3. 呼叫fcntl()和设置为非阻塞
  4. 呼叫listen()
  5. 呼叫epoll_ctl()EPOLL_CTL_ADDEPOLLET | EPOLLONESHOT | EPOLLIN

做出决议THI但现在我发现连接已经生效,但没有收到监听套接字的事件EPOLLIN

我的理解可以选择使用电平触发模式,但我希望得到这个边缘触发模式的工作。

对这个问题可能会有什么想法?

回答

1

EPOLLONESHOT的语义是,一旦通知已经epoll_wait()一些描述被拔掉,你将不得不调用epoll_ctl()EPOLL_CTL_MOD重新启用上描述通知。所以,您可能会因为EPOLLONESHOT已禁用被动/侦听套接字上的通知而丢失连接。 (一般来说,EPOLLONESHOT应该被特殊情况除外使用;它不样板或伏都将被自动添加到一个代码)

此外,利用非阻塞边沿触发语义,关于通知该监听套接字是输入就绪的,需要在循环中调用accept(),直到报告出现EAGAIN错误。只需调用accept()一次就可以将其他连接留在队列中,此外,直到将全新连接添加到该队列后,才会发生另一个边缘触发的事件EPOLLIN事件。 (也就是说,假设EPOLLONESHOT未指定,或者被重新启用的描述符epoll_wait()下一次调用之前的每一次。)

附录消除EPOLLONESHOT肯定是值得尝试的。无论如何你为什么需要它?

+0

谢谢你的回复。我应该澄清,这种虚假故障的情况是与听众端口建立的第一个也是唯一的联系。因此,监听器描述符只能通过EPOLL_CTL_ADD,并且EPOLLONESHOT尚未进入画面。 – user1715664

+0

作为一个实验,我从边缘触发更改为电平触发,仍然看到虚假故障。回顾最近的Linux内核讨论,似乎有一个EPOLLONESHOT错误,可能是负责... http://marc.info/?l=linux-kernel&m=135708457812386&w=2 – user1715664

+0

您是否尝试过第二次连接,看看是否这将套接字唤醒并导致两个成功的accept()?这表明如果连接已经在EPOLL_CTL_ADD点的监听队列中(不太可能,但你永远不知道),边缘触发的通知将不起作用。无论如何你都可以通过调用accept()来解决这个问题(因为它不会阻塞)。但是,一般来说,边缘触发的语义并不总是读/输入端的好主意。 – arayq2