【问题标题】:Is it possible to do epoll on accept event?是否可以在接受事件时进行 epoll?
【发布时间】:2018-05-27 01:29:09
【问题描述】:

假设我已经创建了一个监听套接字:

sock = socket(...);
bind(sock,...);
listen(sock, ...);

是否可以在 sock 上执行 epoll_wait 以等待传入连接?之后如何获取客户端的socket fd?

事情是在我为套接字编写的平台上不能是非阻塞的,但是有超时的工作 epoll 实现,我需要接受连接并在单个线程中使用它,这样它就不会如果出现问题并且无法连接,则挂起。

【问题讨论】:

  • 是的,您需要将套接字设置为 non_blocking 模式,并且在收到任何读取事件后应该执行接受,例如:stackoverflow.com/questions/29729561/…
  • 不需要非阻塞。只需轮询侦听套接字即可可读

标签: c sockets posix epoll


【解决方案1】:

如果不知道这个非标准平台是什么,就不可能确切知道他们给 epoll 调用提供了什么语义。但是在 Linux 上的标准 epoll 上,当传入连接到达时,一个正在监听的套接字会被报告为“可读”,然后你可以通过调用 accept 来接受该连接。如果你让套接字处于阻塞模式,并且在每次调用 accept 之前总是使用 epoll 的级别触发模式检查可读性,那么这应该工作 - 唯一的风险是如果你以某种方式结束当没有连接到达时调用accept,那么你会被卡住。例如,如果有两个进程共享一个侦听套接字,并且它们都尝试accept 同一个连接,则可能会发生这种情况。或者,如果传入连接到达,然后在您调用 accept 之前再次关闭,则可能会发生这种情况。 (可以肯定的是,在这种情况下,Linux 仍然让accept 成功,但这种边缘情况正是我怀疑一个奇怪的平台做一些奇怪的事情的地方。)你想检查这些事情。

非阻塞模式更可靠,因为在最坏的情况下,accept 只是报告没有什么可以接受的。但如果那不可用,那么你也许可以摆脱这样的事情......

【讨论】:

    【解决方案2】:

    因为这个答案是在duckduckgo结果中的第一个。我只是插话说,在 GNU/Linux 4.18.0-18-generic (Ubuntu 18.10) 下。

    异步accept一个传入的连接使用一个必须观察errnoEWOULDBLOCK(11)然后将socket添加到epoll read set。

    这是实现这一点的一小部分方案代码:

    (define (accept fd)
      (let ((out (socket:%accept fd 0 0)))
        (if (= out -1)
            (let ((code (socket:errno)))
              (if (= code EWOULDBLOCK)
                  (begin
                    (abort-to-prompt fd 'read)
                    (accept fd))
                  (error 'accept (socket:strerror code))))
            out)))
    

    上面(abort-to-prompt fd 'read)会暂停协程,并将fd添加到epoll read set,如下:

    (epoll-ctl epoll EPOLL-CTL-ADD fd (make-epoll-event-in fd)))
    

    当协程取消暂停时,代码在中止后继续递归调用自身(在尾部调用位置)

    在我在 Scheme 中工作的代码中,由于我依赖 call/cc 来避免回调,因此涉及的内容更多一些。完整代码在source hut

    就是这样。

    【讨论】:

      猜你喜欢
      • 2015-10-13
      • 2010-09-20
      • 1970-01-01
      • 2014-04-02
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 1970-01-01
      • 2012-12-18
      相关资源
      最近更新 更多