【问题标题】:Using multiple sockets, is non-blocking or blocking with select better?使用多个套接字,选择非阻塞还是阻塞更好?
【发布时间】:2010-12-04 07:38:18
【问题描述】:

假设我有一个服务器程序可以接受来自 10 个(或更多)不同客户端的连接。客户端随机发送数据,服务器接收到这些数据,但可以肯定的是,每次更新都会至少有一个客户端发送数据。服务器不能等待信息到达,因为它还有其他处理要做。除了使用异步套接字之外,我还看到了两个选项:

  1. 使所有套接字都非阻塞。在一个循环中,在每个套接字上调用recv(),如果没有可用数据并且我碰巧得到一些数据,则让它以WSAEWOULDBLOCK 失败,然后保留它。

  2. 让套接字保持阻塞状态。将所有套接字添加到 FD_SET 并调用 select()。如果返回值非零(大多数情况下都是这样),则循环遍历所有套接字以使用FD_ISSET() 找到适当数量的可读套接字,并且只在可读套接字上调用recv()

第一个选项将创建更多对recv() 函数的调用。第二种方法从编程的角度来看是一个更大的痛苦,因为所有的 FD_SETFD_ISSET 循环。

首选哪种方法(或另一种方法)?是否避免让recv() 在非阻塞套接字上失败的开销值得调用select() 的麻烦?

我认为我理解这两种方法,并且我都成功地尝试了两种方法,但我不知道一种方法是否被认为更好或最佳。

【问题讨论】:

    标签: sockets winsock blocking nonblocking


    【解决方案1】:

    我建议改用overlapped IO。然后您可以启动WSARecv(),并提供一个回调函数以在操作完成时调用。更重要的是,由于它只会在您的程序处于警报等待状态时被调用,因此您无需像在线程应用程序中那样担心锁(假设您在主线程上运行它们)。

    但是请注意,您确实需要经常进入这种可警告的等待状态。如果这是您的 UI 线程,请确保在您的消息循环中使用 MsgWaitForMultipleObjectsEx(),并带有 MWMO_ALERTABLE 标志。这将使您的回调有机会运行。在非 UI 线程上,定期调用任何 wait functions 使您进入警报等待状态。

    另请注意,模式对话框通常不会进入警报等待状态,因为它们有自己的消息循环,不会调用MsgWaitForMultipleObjectsEx()。如果您需要在显示对话框时处理网络 IO,请在专用线程上执行所有网络 IO,该线程会定期进入警报等待状态。

    如果出于某种原因,您不能使用重叠 IO - 一定要使用阻塞 select()。在无限循环中使用非阻塞recv() 是对 CPU 时间的不可原谅的浪费。但是,请务必将套接字置于非阻塞模式 - 否则,如果一个字节到达并且您尝试读取两个字节,您可能会意外阻塞。

    您可能还想考虑使用库来抽象出挑剔的细节。例如,libeventboost::asio

    【讨论】:

    • 谢谢。对于这个实现,我不想使用 Overlapped IO,但感谢您的建议。我会调查的。我理解您使用非阻塞模式和 select() 的建议。我的主要问题是我应该无缘无故地调用recv,还是通过调用select()的动作。感谢您的回复!
    • 对其进行了更新以使其更加清晰 - 只需循环使用 recv() 就会将 CPU 固定在 100%,这绝不是一件好事。
    【解决方案2】:

    IO 应该完全阻塞每个连接一个线程,在这种情况下,事件循环本质上是一个 OS 调度程序,或者 IO 应该完全非阻塞,在这种情况下,基于 select/waitformultipleobjects 的事件循环将是在您的应用程序中

    所有中间变体都不是很好维护且容易出错

    当并发连接数量增长并且没有线程上下文切换开销时,完全非阻塞方法的扩展性要好得多,因此在并发连接数不固定的情况下它是可取的。与完全阻塞的方法相比,这种方法的实现复杂度更高。

    对于完全非阻塞 IO,应用程序的核心是一个基于 select/waitformultipleobjects 的事件循环,所有套接字都处于非阻塞模式,所有读/写通常在事件循环线程内完成(以获得最佳性能可以首先直接从请求写入的线程尝试写入)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-13
      • 2011-08-19
      • 2012-11-13
      • 2010-10-31
      • 2013-10-15
      • 2014-10-19
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多