带有轮询的非阻塞套接字

时间:2010-07-29 08:51:59

标签: c sockets posix blocking

几天前,我不得不调查我的应用程序在(显然)处于空闲状态时显示异常高CPU使用率的问题。我将问题跟踪到一个循环,这个循环意味着阻塞recvfrom调用,同时套接字已设置为O_NONBLOCK - 导致旋转锁定。有两种方法可以解决问题:使用pollselect将套接字设置为阻塞或轮询套接字上的可用数据。我选择前者因为它更简单。但我想知道为什么任何人会创建一个非阻塞套接字然后单独轮询它。阻塞套接字是否也这样做?使用非阻塞套接字和轮询组合的用例有哪些?在一般情况下它有什么优势吗?

4 个答案:

答案 0 :(得分:7)

poll()select()与非阻塞文件描述符一起使用会带来两个好处:

  • 您可以设置超时以阻止;
  • 您可以等待任何 set 的文件描述符变得可用。

如果你只有一个文件描述符(套接字)要等待,而你不介意无限期地等待它,那么是;你可以使用阻止电话。

第二个优势实际上是select()和朋友的杀手级用例。这意味着您可以使用单个控制线程来处理多个套接字连接,标准输入和标准输出以及可能的文件I / O.

答案 1 :(得分:2)

我在这里发帖,因为虽然问题很老。它出现在我的谷歌搜索中,并且肯定没有得到正确回答。

接受的答案仅突出了使用非阻塞套接字的两个优点,但并未真正详细说明或回答实际问题。

  • 注意:不幸的是,大多数在线“教程”或代码片段仅包含阻塞套接字代码,因此对非阻塞套接字的了解较少。

关于何时使用一个与另一个相比...通常,阻塞套接字仅用于在线代码片段。在所有(良好)生产应用中,使用非阻塞套接字。我不是一无所知,如果你知道一个使用阻塞套接字的实现(并且确定这很可能与线程组合) - 或者让我们更具体一点,在单个线程中使用阻塞套接字 - 请让我们我知道。

现在我可以给你一个非常容易理解的例子,还有很多其他的例子。我们以游戏服务器为例。无论玩家是否提供输入(鼠标/键盘)来改变游戏状态,游戏都会在游戏状态进行的定期间隔内前进。现在当套接字在多人游戏中发挥作用时 - 如果你使用阻塞套接字,除非玩家发送更新,否则游戏状态不会发展 - 所以如果他们有互联网问题,游戏状态永远不会一直更新并传播给所有玩家的变化。你会有一个相当不稳定的经历。

现在使用非阻塞套接字,您可以在单线程上运行游戏服务器,更新游戏状态以及套接字,使用...假设50毫秒超时间隔 - 并且套接字数据仅从连接用户实际发送的东西,然后输入服务器模拟,处理并输入游戏状态计算下一个滴答。

答案 2 :(得分:1)

  

导致旋转锁定。

这种情况通常被称为紧密循环

  

有两种方法可以解决问题:使用poll或select将套接字设置为阻塞或轮询套接字上的可用数据。我选择了前者,因为它更简单。

您确定其他代码部分尚未使用poll()(或select())并期望套接字处于非阻塞模式吗?

否则,是的,切换到阻止模式是最简单的解决方案。

最佳向后兼容的解决方案在调用recvfrom()之前使用poll()等待套接字变得可读。这样可以确保代码的其他部分可以像以前一样精确地工作。

  

但我想知道为什么任何人会创建一个非阻塞套接字然后单独轮询它。阻塞套接字是否也这样做?

对于recvfrom()的情况,我不知道有什么重大差异。

  

使用非阻塞套接字和轮询组合的用例有哪些?在一般情况下,它有什么优势吗?

可能是一个简单的编码错误。或者有人可能认为在紧密循环中重新调整会以某种方式提高性能。

答案 3 :(得分:0)

将套接字设置为nonblocking总是更好,因为即使阻塞套接字有时会变为就绪状态(当数据到达但有校验和错误而被丢弃时) - 即使没有数据要读取。所以把它nonblocking,等待通过民意调查获得数据,然后阅读。我认为这是主要优势。