socket发送呼叫被阻塞了这么久

时间:2012-06-14 16:56:46

标签: c++ linux sockets tcp

我每隔10秒在套接字上发送2个字节的应用数据(阻塞),但发送呼叫在下面的最后一个实例中被阻止超过40秒。

  • 2012-06-13 12:02:46.653417 | INFO |发送前
  • 2012-06-13 12:02:46.653457 | INFO | after send(2)
  • 2012-06-13 12:02:57.566898 | INFO |发送前
  • 2012-06-13 12:02:57.566962 | INFO | after send(2)
  • 2012-06-13 12:03:08.234060 | INFO |发送前
  • 2012-06-13 12:03:08.234101 | INFO | after send(2)
  • ** 2012-06-13 12:03:19.010743 | INFO | before send
  • 2012-06-13 12:04:00.969162 | INFO | after send(2)**

计算机(linux)上的tcp默认发送缓冲区大小为65536。

2字节数据是服务器的心跳,服务器希望客户端每15秒至少发送一次HB。

另外,我没有禁用naggle的算法。

问题是 - 发送呼叫能否像40秒一样被阻止?它只是偶尔发生,它发生在接近12个小时的运行之后。

我知道的发送调用应该只是将数据复制到TCP发送缓冲区。

每10秒调用一次。不,它不是逐渐减慢发送电话。它突然发生一次,然后由于另一侧的插座关闭,所以应用程序退出。

int publish(char* buff, int size) const {
      /* Adds the 0x0A to the end */
      buff[size]=_eolchar;

      if (_debugMode)
      {
          ACE_DEBUG((MY_INFO "before send\n"));
      }

      int ret = _socket.send((void*)buff, size+1);

      if (_debugMode)
      {
          ACE_DEBUG((MY_INFO "after send (%d)\n", ret));
          //std::cout << "after send " << ret << std::endl;
      }

      if (ret < 1)
      {
          ACE_DEBUG((MY_ERROR "Socket error, FH going down\n"));
          ACE_OS::sleep(1);
          abort();
      }
      return ret;
 }

2 个答案:

答案 0 :(得分:2)

使用阻塞send()调用时,从应用程序的角度来看,您可以将远程TCP缓冲区,网络和本地发送TCP缓冲区视为一个大缓冲区。

也就是说,如果远程应用程序在从其TCP缓冲区读取新字节时被延迟,最终本地TCP缓冲区将变得(几乎)满。如果您尝试send()溢出TCP缓冲区的新有效负载,send()实现(内核系统调用)将不会将焦点返回到您的应用程序,直到TCP缓冲区获得足够的空间来存储有效载荷。

达到该状态的唯一方法是远程应用程序无法读取足够的字节数。 test 环境中的典型情况是远程应用程序在断点处暂停...: - )

这就是我们所说的 SLOW CONSUMER 问题。如果您分享该诊断,那么有多种方法可以解决该问题:

  1. 如果您可以控制远程应用程序,请快速 ,以免本地应用程序被阻止。
  2. 如果您无法控制远程应用程序,则可能有多个答案:
    • 您自己的需要可以阻止长达40秒。
    • 如果不是这样,您需要使用send()系统调用的解除阻止版本。从这里开始,有多种可能的政策;我在下面描述一个。 (等一下!:-))
  3. 您可以尝试使用动态数组作为假发送TCP FIFO,并在发送调用返回EWOULDBLOCK时增长。在这种情况下,您可能必须使用select()系统调用来检测远程应用程序何时跟上速度并首先向其发送看不见的数据。

    这里的简单publish()函数可能有点棘手(虽然在大多数网络应用程序中很常见)。您还必须知道,无法保证动态缓冲区增长到您不再拥有任何可用内存的程度,然后您的本地应用程序可能会崩溃。 “实时”网络应用程序中的典型策略是为缓冲区选择任意最大大小,以便在到达时关闭TCP连接,从而避免本地应用程序耗尽可用内存。明智地选择最大值,因为它取决于潜在的慢速消费者连接的数量。

答案 1 :(得分:1)

以下(以及我现在不提及的更多内容)被视为阻止系统调用:
发送,连接,接收,接受。

这意味着他们可以根据需要阻止,直到指定的工作完成。 所以是的,发送可以阻止40秒或更长时间,具体取决于发送数据所需的时间;虽然我不知道为什么它会在你的具体情况下阻止那么久。

如果你想避免这种阻塞,我建议你阅读有关异步套接字和I / O的内容。 他们可能会解决你的部分问题。