c++ - windows下奇怪的tcp死锁

标签 c++ windows sockets tcp deadlock

我们在 LAN 上移动大量数据,并且必须非常快速和可靠地进行。目前我们使用在 C++ 中实现的 Windows TCP。使用大型(同步)发送比一堆较小的(同步)发送移动数据要快得多,但会经常出现大时间间隔(0.15 秒)的死锁,导致整体传输速率直线下降。这种僵局发生在非常特殊的情况下,这让我相信它应该是完全可以避免的。更重要的是,如果我们真的不知道原因,我们也不知道它不会在某个时候发生较小的发送。谁能解释这个僵局?

死锁描述(好的,僵尸锁定,它并没有死,但是它停止了 .15 秒左右,然后又开始了)

  1. 接收方发送一个ACK。
  2. 发送方发送一个包含消息结束的数据包(设置推送标志)
  3. 对 socket.recv 的调用大约需要 0.15 秒(!)返回
  4. 关于调用返回ACK的时间由接收方发送
  5. 发送方的下一个数据包终于发送了(为什么要等待?tcp 窗口很大)

关于 (3) 的奇怪之处在于,通常该调用根本不会花费太多时间并且接收到完全相同数量的数据。在一台 2Ghz 的机器上,有 3 亿条指令的时间值(value)。我假设调用不会(天堂禁止)等待接收到的数据在返回之前被确认,因此 ack 必须等待调用返回,或者两者都必须被其他东西延迟。

当有第二个数据包(同一消息的一部分)到达 1 和 2 之间时,问题永远不会发生。这部分非常清楚地表明它与 Windows TCP 不会发回的事实有关无数据 ACK,直到第二个数据包到达或 200 毫秒计时器到期。然而,延迟小于 200 毫秒(更像是 150 毫秒)。

第三个不合时宜的角色(在我看来是真正的罪魁祸首)是 (5)。肯定会在 0.15 秒结束之前调用 Send,但数据永远不会在 ack 返回之前到达线路。对我来说,这是这个僵局中最奇怪的部分。它不是 tcp 阻塞,因为 TCP 窗口很大,因为我们将 SO_RCVBUF 设置为 500*1460 之类的值(仍然低于 meg)。数据进入速度非常快(基本上有一个循环通过发送发送数据)所以缓冲区应该几乎立即填满。 Msdn 提到在决定发送何时到达线路时使用了各种“启发式”,并且已经挂起的发送+完整的缓冲区将导致发送阻塞,直到数据到达线路(否则发送显然只是将数据复制到 tcp发送缓冲区并返回)。

无论如何,为什么发件人在 0.15 秒的暂停期间实际上没有发送更多数据对我来说是最奇怪的部分。上面的信息是通过 wireshark 在接收端捕获的(当然除了记录在文本文件中的 socket.recv 返回时间)。我们尝试将发送缓冲区更改为零并关闭发送方的 nagel(是的,我知道 nagel 是关于不发送小数据包 - 但我们尝试关闭 nagel,以防这是影响消息是否会影响消息的未声明“启发式”的一部分被发布到线路上。从技术上讲,微软的 nagel 是如果缓冲区已满并且有一个未完成的 ACK,则不会发送一个小数据包,所以这似乎是可能的)。

最佳答案

发送阻塞直到收到前一个ACK 几乎可以肯定表明 TCP 接收窗口已满(您可以使用 Wireshark 分析网络流量来检查这一点)。

无论您的 TCP 窗口有多大,如果接收应用程序处理数据的速度不如数据到达时快,则 TCP 窗口最终会填满。我们在这里说话有多快?接收方对数据做了什么? (如果您正在将接收到的数据写入磁盘,那么您的磁盘很可能无法跟上千兆网络的全速传输)。


好的,所以您有一个 730,000 字节的接收窗口,并且您正在以 480Mbps 的速度传输数据。这意味着完全填满您的窗口只需要 12 毫秒 - 因此当接收端发生 150 毫秒延迟时,接收窗口几乎立即填满并导致发送方停止。

因此,您的根本原因是在安排接收过程时延迟了 150 毫秒。有很多事情可能会导致这种情况(可能就像内核需要将脏页刷新到磁盘以便为您的应用程序创建更多空闲页一样简单);您可以尝试增加进程的调度优先级,但不能保证一定会有帮助。

关于c++ - windows下奇怪的tcp死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2822915/

相关文章:

android - Google Android USB 驱动程序和 ADB

java - spring roo windows安装 "Could not find or load main class"

java - ObjectInputStream 无法识别我的对象数据格式

java/android TCP sockets - 检测服务器是否离线

c++ - 非模板的模板定义

c++ - 创建对象指针数组 C++

c++ - 为什么需要转发返回值

windows - Powershell Git 钩子(Hook)退出代码

c++ - std::regex 未按预期工作

c - 非终止 while 循环,同时使用 recv