【问题标题】:select(), recv() and EWOULDBLOCK on non-blocking sockets非阻塞套接字上的 select()、recv() 和 EWOULDBLOCK
【发布时间】:2010-10-29 00:49:49
【问题描述】:

我想知道下面的场景是不是真实的?!

  1. 非阻塞 TCP 套接字上的 select() (RD) 表示套接字已准备就绪
  2. 尽管调用了 select(),但在 recv() 之后会返回 EWOULDBLOCK

【问题讨论】:

    标签: c++ c sockets


    【解决方案1】:

    对于recv(),你会得到EAGAIN 而不是EWOULDBLOCK,是的,这是可能的。由于您刚刚检查了select(),因此发生了以下两件事之一:

    • 其他东西(另一个线程)耗尽了select()recv() 之间的输入缓冲区。
    • 在套接字上设置了接收超时,并且在没有接收到数据的情况下过期。

    【讨论】:

    • 如果超时,select()返回0,所以我不担心。
    • #define EWOULDBLOCK EAGAIN /* 操作会阻塞 */ -- 在许多操作系统上都可以找到
    • POSIX.1-2001 允许在读取非阻塞套接字时返回任一错误(并且不要求它们具有相同的值。)
    • 有趣的是,它在许多操作系统上都被定义为相同的错误代码,这意味着您不能将其放入 switch 块中以实现可移植性。
    【解决方案2】:

    这是可能的,但仅在您有多个线程/进程试图从同一个套接字读取的情况下。

    【讨论】:

    • 很高兴听到这个消息。我的应用程序是单线程的,所以我很好。
    【解决方案3】:

    在 Linux 上,我读到它甚至记录了这可能发生。

    看到这个问题:

    Spurious readiness notification for Select System call

    【讨论】:

      【解决方案4】:

      我知道一个流行的桌面操作中的错误,其中O_NONBLOCK TCP 套接字,特别是那些在环回接口上运行的套接字,有时可以在select() 报告套接字已准备好读取之后从recv() 返回EAGAIN .就我而言,这发生在对方半关闭发送流之后。

      有关更多详细信息,请参阅我的 OCaml 网络应用程序环境分发的 NX 库中的 t_nx.ml 的源代码。 (link)

      【讨论】:

        【解决方案5】:

        虽然我的应用程序是单线程的,但我注意到所描述的行为在 RHEL5 中并不少见。使用设置为 O_NONBLOCK(唯一设置的套接字选项)的 TCP 和 UDP 套接字。 select() 报告套接字已准备好,但随后的 recv() 返回 EAGAIN。

        【讨论】:

          【解决方案6】:

          是的,这是真的。这是发生这种情况的一种方式:

          未来对 TCP 协议的修改增加了一方“撤销”其发送的信息的能力,前提是该信息尚未被另一方的应用层接收。此功能是在连接上协商的。对方向你发送一些数据,你会得到一个select 命中。在您致电recv 之前,对方会使用这个新的扩展名“撤销”数据。您的 read 收到“将阻止”错误,因为没有可供读取的数据。

          select 函数是一个状态报告函数,不附带未来保证。假设现在点击select 可以确保后续操作不会阻塞,这与以这种方式使用任何其他状态报告功能一样无效。就像使用access 尝试确保后续操作不会因权限错误而失败或使用statfs 尝试确保后续写入不会因磁盘已满而失败一样糟糕。

          【讨论】:

            【解决方案7】:

            在两个线程从套接字读取的多线程环境中是可能的。这是一个多线程应用程序吗?

            【讨论】:

            • 即使套接字超时,而不仅仅是select()的参数?如果在select()recv() 之间发生超时怎么办?
            • 在这种情况下,您不应该看到这种行为。
            • “套接字超时”是什么意思?
            【解决方案8】:

            如果您不在此套接字上的 select() 和 recv() 之间调用任何其他系统调用,则 recv() 将永远不会返回 EAGAIN 或 EWOULDBLOCK。

            我不知道 recv-timeout 是什么意思,但是,POSIX 标准在这里没有提到它,所以你可以安全地调用 recv()。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-09-13
              • 2016-06-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多