阻塞和非阻塞套接字有什么区别? (适用于realz版)

时间:2016-02-09 09:58:36

标签: linux windows networking boost udp

在每个人都认为这是一个重复之前让我说我知道我的网络编程的公平份额,这个问题是我尝试解决的东西,即使在找到"解决方案"之后也会让我感到困惑。

设置

我花了最后几周写了一些胶水代码,将大型工业系统纳入我们目前的设置。该系统由Windows XP计算机(PC A)控制,该计算机通过以2000 Hz的频率发送稳定的UDP数据包流从Ubuntu 14.04系统(PC B)进行控制。它使用包含系统当前状态的UDP数据包进行响应。

注意确保保持2000 Hz速率,因为在3ms超时后系统发生故障并返回安全状态。这包括衡量和核算std::this_thread::sleep_for中的不准确性。测量表明,目标利率只有0.1%的推导。

观察

当我开始从系统接收状态响应时,问题就开始了。 PC B 的控制方看起来大致如下:

forever at 2000Hz {
  send current command;
  if ( socket.available() >= 0 ) {
    receive response;
  }
}

编辑2 或以实际代码:

auto cmd_buf = ...
auto rsp_buf = ...

while (true) {
   // prepare and send command buffer
   cmd_buf = ...
   socket.send(cmd_buf, endpoint);

   if (socket.available() >= 0) {
      socket.receive(rsp_buf);
      // the results are then parsed and stored, nothing fancy
   }

   // time keeping
}

问题是,只要代码的接收部分出现在 PC B 上, PC A 在尝试分配接收缓冲区。此外,它引发了错误,指出错过了超时,这可能是因为数据包没有到达控制软件。

只是为了强调这种陌生感:在这种情况下, PC A 是pc 发送 UDP数据包。

编辑以回应EJP:这是(现在)工作设置。它最初是:

forever at 2000Hz {
  send current command;
  receive response;
}

但是当收到回复(阻止)时,错过了截止日期。因此可用性检查。

尝试的另一件事是以单独的线程接收:

// thread A
forever at 2000Hz {
  send current command;
}

// thread B 
forever {
  receive response;
}

显示与第一个版本相同的行为。

解决方案

解决方案是将 PC B 上的套接字设置为非阻塞模式。一条线和所有问题都消失了。

我很确定即使在阻止模式下也能满足截止日期。当只涉及一个套接字时,阻塞和非阻塞模式之间应该没有性能差异。即使检查套接字中的可用数据比非阻塞模式要多几微秒,但在准确地满足整个截止日期时也不应该有所不同。

现在......这里发生了什么?

1 个答案:

答案 0 :(得分:0)

如果我正确阅读您的代码并参考此代码:

forever at 2000Hz {
  send current command;
  receive response;
}

检查阻塞和不阻塞套接字之间的区别。使用阻塞套接字,您可以发送当前命令,然后等待响应。到这个时候我猜你已经错过了2kHz的目标。

现在在非阻塞套接字中,您发送当前命令,尝试接收接收缓冲区中的任何内容,但如果没有任何内容,则立即返回并继续紧密的2kHz发送循环。这就解释了为什么您的工业控制系统在非阻塞代码中工作正常。