2

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

  1. 称呼socket()
  2. 称呼bind()
  3. 调用fcntl()并设置为非阻塞
  4. 打电话epoll_ctl()EPOLL_CTL_ADD_EPOLLET | EPOLLONESHOT | EPOLLIN
  5. 称呼listen()

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

  1. 称呼socket()
  2. 称呼bind()
  3. 调用fcntl()并设置为非阻塞
  4. 称呼listen()
  5. 打电话epoll_ctl()EPOLL_CTL_ADD_EPOLLET | EPOLLONESHOT | EPOLLIN

解决了这个问题,但现在我看到了建立连接EPOLLIN但未收到侦听器套接字的事件的虚假故障。

我知道可以选择使用电平触发模式,但我想让它适用于边缘触发模式。

关于这个问题可能是什么的任何想法?

4

1 回答 1

1

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

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

附录消除 EPOLLONESHOT 当然值得一试。为什么你还需要它?

于 2013-01-08T18:35:02.980 回答