什么是TCP窗口更新?

php*_*der 17 java sockets networking tcp wireshark

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

当客户端连接服务器时,它会以Gzip格式向其发送级别文件.在发送级别的大约94个数据包中,我的服务器使用ArrayIndexOutOfBoundsException崩溃客户端.根据原始服务器的捕获文件,它会在该点发送TCP窗口更新.什么是TCP窗口更新,以及如何使用SocketChannel发送一个?

小智 59

TCP窗口用于连接上的对等体之间的流控制.对于每个ACK数据包,主机将发送"窗口大小"字段.该字段表示主机在满之前可以接收的数据字节数.发件人不应发送超过该数量的数据.

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

这是一个TCP停顿.它可能由于很多原因而发生,但最终它只意味着发送者的传输速度比接收者正在读取的速度快.

一旦接收端的应用程序回到从套接字读取,它将消耗一些缓冲数据,这释放了一些空间.接收器然后将发送"窗口更新"分组以告知发送器它可以传输多少数据.发送方开始发送其缓冲数据,流量应正常流动.

当然,如果接收器一直很慢,你可以得到重复的停顿.

我已经说过,好像发送方和接收方不同,但实际上,两个对等方都在与每个ACK数据包交换窗口更新,并且任何一方都可以填充其窗口.

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

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

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

  • 我的bug-fu告诉我,最后一段很可能已经解决了这个问题. (3认同)

Aar*_*lla 6

这在TCP/IP堆栈中发生得非常深刻; 在您的应用程序(服务器和客户端)中,您不必担心TCP窗口.错误必须是别的.