什么是 TCP 窗口更新?

2024-02-25

我正在为 Java 游戏制作自己的自定义服务器软件(游戏和原始服务器软件是用 Java 编写的)。没有任何可用的协议文档,因此我必须使用 Wireshark 读取数据包。

当客户端连接时,服务器会向其发送 Gzip 格式的关卡文件。在发送关卡大约 94 个数据包时,我的服务器使客户端崩溃并出现 ArrayIndexOutOfBoundsException。根据原始服务器的捕获文件,它大约在此时发送 TCP 窗口更新。什么是 TCP 窗口更新?如何使用 SocketChannel 发送窗口更新?


TCP 窗口用于连接上对等点之间的流量控制。对于每个 ACK​​ 数据包,主机将发送一个“窗口大小”字段。该字段表示主机在满之前可以接收多少字节的数据。发送方不应发送超过该数量的数据。

如果客户端接收数据的速度不够快,窗口可能会变满。换句话说,当应用程序不执行从套接字读取数据以外的其他操作时,TCP 缓冲区可能会被填满。当这种情况发生时,客户端将发送一个设置了“窗口已满”位的 ACK 数据包。此时,服务器应该停止发送数据。任何发送到具有完整窗口的机器的数据包都会not被承认。 (这将导致行为不良的发送方重新传输。行为良好的发送方只会缓冲传出数据。如果发送端的缓冲区也填满,则发送应用程序在尝试向套接字写入更多数据时将阻塞!)

这是 TCP 停顿。发生这种情况的原因有很多,但最终它只是意味着发送方的传输速度比接收方的读取速度快。

一旦接收端的应用程序恢复从套接字读取数据,它将耗尽一些缓冲的数据,从而释放一些空间。然后接收方将发送一个“窗口更新”数据包,告诉发送方它可以传输多少数据。发送方开始传输其缓冲的数据,并且流量应该正常流动。

当然,如果接收器持续缓慢,您可能会遇到重复的停顿。

我这样表述就好像发送方和接收方是不同的,但实际上,两个对等方都在与每个 ACK​​ 数据包交换窗口更新,并且任何一方都可以填满其窗口。

总体信息是您不需要直接发送窗口更新数据包。欺骗一个实际上是一个坏主意。

关于您看到的异常...它不太可能是由窗口更新数据包引起或阻止的。但是,如果客户端读取速度不够快,您可能会丢失数据。在您的服务器中,您应该检查 Socket.write() 调用的返回值。它可能小于您尝试写入的字节数。如果发送方的传输缓冲区已满,就会发生这种情况,这可能在 TCP 停顿期间发生。您可能会丢失字节。

例如,如果您尝试在每次调用 write 时写入 8192 字节,但其中一个调用返回 5691,则您需要在下一次调用时发送剩余的 2501 字节。否则,客户端将看不到该 8K 块的剩余部分,并且您的文件在客户端上将比在服务器端上短。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是 TCP 窗口更新? 的相关文章

随机推荐