我的应用程序(在 Win2k12 上运行)中有一个通过 TCP 的下载流。
问题是发送方会因为超时而关闭连接。
我使用 wireshark 查看了 2 台不同服务器上发生的情况(在一台服务器上运行正常,而在另一台服务器上超时)。我注意到两台服务器上的行为相同:
下载开始时,一切似乎都正常,窗口大小为 64k 并保持一段时间不变,段得到确认。然后在某个时刻,窗口大小开始减小,直到为 0。(据我所知,这是正常的,接收方无法跟上发送方。)但是,在应用程序读取整个缓冲区之前,没有来自接收方的 ACK 或窗口更新消息,然后窗口更新再次通告 64k 窗口大小。然后它重新开始。窗口大小减小直到为零。
这对我来说似乎不对。当应用程序从缓冲区读取时,它应该有可用空间,并且应该发送窗口更新,以便发送方可以发送下一个段。
我不明白的另一件事是故障服务器上的行为。此服务器在每个这样的周期中都会通告越来越大的窗口大小,在超时之前的最后一个周期中,窗口大小约为 800 000。发生超时是因为缓冲区清空速度不够快。但我不知道为什么此服务器上的窗口大小会增加?服务器上是否有设置可以防止这种情况发生?
我的假设正确吗,还是我对 TCP 协议有误解?任何解决此问题的想法都值得赞赏。
谢谢。
答案1
如果接收进程处理数据的速度不如数据在网络上传输的速度快,则窗口应该随着数据包的接收而变小,直到接收缓冲区已满,窗口为 0。在这种情况下,服务器仍然应该确认接收到的数据,这样发送方就知道不要重新传输它。
一旦窗口变为 0,接收端就不应该在应用程序从流中读取另一个字节时立即通告窗口中还有空间容纳更多数据。它至少应该等到有足够的可用空间来匹配一个 MTU 大小的数据包。等待的时间比这长得多并不是一个好主意。
在传输过程中动态调整内存分配大小是明智的行为。但是,算法应该致力于收敛到一个足够大的大小,以免造成瓶颈,但不应该比这个大太多。你所描述的波动不应该发生。如果接收应用程序无法跟上数据的到达,那么窗口大小就不应该增加。
发送方不应该在未先发送几个保持活动数据包的情况下使连接超时。如果发送方在未发送保持活动数据包的情况下使连接超时,那么我会说发送方存在错误。如果发送方确实发送了保持活动数据包,但接收方没有响应,那么我会说接收方存在错误。
您是否检查了连接两端的通信以确保没有任何严重的数据包丢失导致超时?