【发布时间】:2012-07-15 09:26:21
【问题描述】:
简而言之: 服务器成功调用 ::send() 但数据没有通过电缆输出。客户端在几秒钟后发送它的退出命令,因为它没有收到任何东西并且该命令被服务器正确接收。
详细说明: 服务器每 1/10 秒向其客户端发送一个命令,每秒发送一个心跳。客户端只为心跳返回一个 ack。我们修改了服务器应用程序以记录发送和接收的每个命令,并且我们使用 Wireshark 记录了 pc 的流量。我们可以将每个记录的命令与一个 TCP 数据包匹配,直到问题出现。问题一次只影响一个客户端。数据继续与其他客户端正常流动。连接通常会在遇到麻烦前几分钟工作。从客户端启动到关闭(即几天),连接应该可以工作。
当问题发生时,日志文件包含预期的命令,但 Wireshark 转储不包含任何内容。下图显示了一个客户端的流量。红线是流量停止时,但服务器继续调用 ::send() 成功。 大约 4 秒后,客户端超时并关闭连接。它发送一个退出命令,服务器正常接收。
更让我困惑的是包含退出命令的数据包没有通过 TCP ACK 数据包确认。就好像 TCP 连接在发送端完全阻塞了一样。重传是这种堵塞的结果,但即使是建立新连接的 TCP SYN 也没有得到正确处理,也没有得到简单的 TCP ACK。
大约 30 秒后,问题消失,SYN 数据包最终被接受,通信继续使用新连接。
这已在各种 Windows 版本上进行了测试。在测试期间,使用了远程桌面会话,并且从未因同样的问题而断开连接。它保持连接数小时没有任何问题。当客户端通过无线网桥时,问题更加频繁。我们在无线端点的两侧都使用了 Wireshark,我们没有看到可以解释更高断开率的重传或丢包。
当许多客户端连接到同一个网桥时,它们不会同时发生故障。一次只有一个。所以无线噪音似乎不是一个解释。我们可以在 Wireshark 转储中看到一些重传,但通信照常继续,在问题发生之前没有重传。接入点连接到服务器的交换机。客户端电脑和服务器电脑不使用无线网卡。
一直以来,我们一直认为偶尔的断线是由于网络造成的,但是越来越多的安装是无线的,现在断线频繁到给用户带来麻烦。
我们尝试了启用和不启用 Windows 防火墙。即使防火墙被禁用,我们也添加了端口例外。客户端或服务器都没有防病毒软件。
【问题讨论】:
-
嗯,“就好像 TCP 连接在发送端完全阻塞”听起来完全正确 - 服务器 tx 窗口已关闭以防止任何进一步的传输,直到收到来自客户端的 ACK,但发送() 只要在服务器上对其数据进行缓冲,就会成功。客户端 rx 线程卡在某个地方?
-
但是,从 Wireshark 转储中,我看到客户端的接收窗口为 1002 字节,所以据我所知,它不应该是这样。顺便说一句,我不知道为什么接收窗口这么小,但它是这样工作的。服务器发送的命令的字节数比这少。
-
接收窗口大小 1002 非常小。最初是 5840 字节吗(就像在下一个 SYN 中一样)?因为服务器每秒调用发送 10 次,可能服务器的发送缓冲区中超过 1002 字节,并且 TCP 堆栈等待 ACK 因为接收窗口(1002)不允许发送下一个段(1003 - 1460 字节)
-
是的,它从 5840 字节开始,在最初的几分钟内增加到 64k,但由于某种原因(可能是无线噪声),它通常会减少到 1002 字节。但它在 1002 字节处工作了很多分钟。这些命令的大小为 68 和 56 字节,因此它们应该通过。 Wireshark 在服务器 pc 上运行,我们看到来自客户端的最后一个 TCP ACK。我也在客户端记录,我没有看到任何数据包发送但服务器pc没有收到。
-
有问题的盒子上是否有多个接口?在为无线和有线接口分配相同 IP 的环境中,我也有类似的行为(通常不是一个好主意,但有时很方便)。