TCP套接字出现非常奇怪的断开连接问题

10
简单来说:服务器成功调用了::send(),但数据没有传输出去。客户端在几秒钟后发送其退出命令,因为它没有接收到任何内容,并且该命令被服务器正确地接收。
详细来说:服务器每1/10秒向其客户端发送一个命令和每秒一个心跳包。客户端仅对心跳包返回确认。我们修改了服务器应用程序以记录每个发送和接收的命令,并使用Wireshark记录了PC的流量。我们可以将每个记录的命令与TCP数据包匹配,直到问题出现。问题一次只会影响一个客户端。其他客户端的数据仍然正常传输。连接通常在几分钟内正常工作,然后发生问题。连接应该从客户端引导时开始工作,直到关闭(即数天)。
当问题发生时,日志文件包含预期的命令,但Wireshark转储不包含任何内容。下图显示了一个客户端的流量。红线是流量停止的时刻,但服务器仍然成功调用::send()。大约4秒钟后,客户端超时并关闭连接。它发送一个退出命令,服务器正常接收。
更令我困惑的是,包含退出命令的数据包未收到TCP ACK数据包的确认。就好像TCP连接在发送端完全被堵塞了一样。重传是这种堵塞的结果,但即使用于建立新连接的TCP SYN也没有得到正确处理,并且没有得到简单的TCP ACK。
大约30秒后,问题消失了,SYN数据包最终被接受,使用新连接继续通信。
这在各种Windows版本上进行了测试。在测试期间,使用远程桌面会话,并且从未因同样的问题而断开连接。它可以持续连接数小时而不会出现任何问题。当客户端通过无线桥接时,问题更加频繁。我们在无线终点两侧使用Wireshark,但看不到解释更高的断开率的任何重传或数据包丢失。
当许多客户端连接到同一个桥接器时,它们不会同时失败。每次只有一个。因此,无线噪声似乎并不能解释这种情况。我们可以在Wireshark转储中看到一些重传,但通信仍然按照惯例进行,并且在问题发生之前没有重传。一个接入点连接到服务器的交换机上。客户端PC和服务器PC均不使用无线网络卡。
长期以来,我们认为偶尔的断开连接是由于网络原因造成的,但越来越多的安装是无线的,断开连接现在变得如此频繁,以至于给用户带来了问题。 我们尝试启用和禁用Windows防火墙。即使防火墙已禁用,我们也添加了端口例外。客户端和服务器都没有反病毒软件。

嗯,“就好像TCP连接在发送端完全被堵塞了”听起来非常正确——服务器tx窗口已经关闭,以防止在收到客户端的ACK之前进行任何进一步的传输,但只要服务器有数据缓冲区,send()函数就会成功。客户端rx线程可能卡在某个地方了? - Martin James
是的,它从5840字节开始,在前几分钟内增加到64k,但由于某些原因(可能是无线干扰),它经常降至1002字节。但它在1002字节下工作了很多分钟。命令大小为68和56字节,所以它们应该通过。Wireshark在服务器PC上运行,我们看到客户端的最后一个TCP ACK。我还在客户端记录了,但我没有看到任何数据包被发送但未被服务器PC接收。 - PRouleau
这些盒子上有多个接口吗?我在一些分配相同IP地址给无线和有线接口的环境中遇到过类似的行为(通常不是一个好主意,但有时很方便)。 - Tim Ruddick
你解决了这个问题吗?我有一个类似的问题。 - meka
@meka 我们没有找到原因也没有解决办法。希望这在实际应用中不会太频繁发生。 - PRouleau
显示剩余3条评论
1个回答

1

轮,这在一定程度上是神秘的一部分。在我的实验中,我已经将保持活动状态更改为每秒1次(间隔为1秒,总共10次)。在正常情况下,它不应该触发,因为心跳必须每秒被确认。我希望它能有所帮助(至少在4秒钟没有任何事情发生时进行故障排除),但我在转储中没有看到任何“保持活动”的数据包。 - PRouleau
哎呀,我刚才看到了这段文字:“请记住,在Linux中,保持连接的支持不是默认行为。”我得检查一下是否可以在客户端上操作套接字。 - PRouleau
是的,我不得不在Ubuntu上激活保持连接功能。他们有一个很好的C代码示例。我正在尝试查看我的服务器端是否能够感知到断开连接。如果成功了,我会向您更新任何信息。 - enthusiasticgeek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接