TCP窗口用于连接上的对等体之间的流控制.对于每个ACK数据包,主机将发送一个“窗口大小”字段.该字段表示主机在完整数据之前可以接收多少字节的数据.发送方不应发送超过该数量的数据.
如果客户端没有足够快地接收到数据,窗口可能会变满.换句话说,TCP缓冲区可以在应用程序关闭时填充,而不是从其套接字读取.当发生这种情况时,客户端将发送一个设置了“窗口满”位的ACK数据包.在这一点上,服务器应该停止发送数据.发送到具有完整窗口的机器的任何数据包将不被确认. (这将导致发送方发送者的重传不佳,一个行为良好的发件人只会缓冲传出的数据,如果发送方的缓冲区也被填满,那么发送应用程序在尝试向套接字写入更多的数据时会阻塞!)
这是一个TCP档.它可能发生很多原因,但最终只是意味着发送方的传输速度比接收机读取速度要快.
一旦接收端的应用程序回到从套接字读取,它将耗尽一些缓冲的数据,这释放了一些空间.然后,接收方将发送一个“窗口更新”数据包,以便向发送者传送多少数据.发送方开始发送其缓冲数据,流量应正常流动.
当然,如果接收机一直很慢,你可以得到重复的档位.
我已经写了这个,就像发送者和接收者是不同的,但实际上,两个对等体正在与每个ACK数据包交换窗口更新,任一方都可以填满窗口.
整体消息是,您不需要直接发送窗口更新数据包.欺骗一个人其实是一个坏主意.
关于你看到的例外,它不太可能是窗口更新包引起或阻止.但是,如果客户端的阅读速度不够快,可能会丢失数据.在您的服务器中,您应该从Socket.write()调用中检查返回值.它可能小于您要写入的字节数.如果发送者的发送缓冲区已满,这可能发生在TCP停顿期间.你可能会丢失字节.
例如,如果您尝试在每次调用写入时写入8192个字节,但其中一个调用返回5691,则需要在下次调用时发送剩余的2501个字节.否则,客户端将不会看到该8K块的其余部分,并且您的文件在客户端将比在服务器端更短.