侦听器套接字上的Epoll_wait()和虚假的失败



我看到epoll_wait()和侦听器套接字之间的以下交互。创建侦听器套接字的事件顺序如下:

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

有后台线程为这个套接字和其他线程调用epoll_wait(),如果一个线程在步骤4和5之间这样做,那么侦听器套接字将收到EPOLLHUP事件。将序列更改为:

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

解决了这个问题,但是现在我看到了虚假的失败,其中建立了连接,但是侦听器套接字没有接收到EPOLLIN事件。

我理解可以选择使用电平触发模式,但我想让这个工作在边缘触发模式。

有什么想法吗?

EPOLLONESHOT的语义是,一旦epoll_wait()为某些描述符拉出通知,您将不得不使用EPOLL_CTL_MOD调用epoll_ctl()重新启用该描述符上的通知。因此,您可能只是因为EPOLLONESHOT在被动/侦听套接字上禁用了通知而丢失连接。(一般情况下,除特殊情况外,EPOLLONESHOT不应使用;自动添加到代码中不是样板或巫术)

此外,使用非阻塞边缘触发语义,在通知侦听套接字已准备好输入时,需要在循环中调用accept(),直到报告EAGAIN错误。只调用一次accept()可能会将其他连接留在队列中,而且,在将一个全新的连接添加到该队列之前,不会发生另一个边缘触发的EPOLLIN事件。(也就是说,假设没有指定EPOLLONESHOT,或者在下次调用epoll_wait()之前每次都重新启用描述符。)

附录消除epollonshot当然值得一试。你到底为什么需要它?

最新更新