TCP滑动窗口
概述
TCP进行数据发送,为了提高数据传输的效率,采用了一种叫做滑动窗口的机制来进行数据发送。
滑动窗口用于做流量控制与乱序重排
- 保证TCP的可靠性
- 保证TCP的流控特性
RTT和RTO
- RTT
发送一个数据包到收到对应的ACK所花费的时间 - RTO
重传时间间隔
窗口数据的计算过程
接收方还能接收的窗口大小
AdvertisedWindow = MaxRcvBuffer - (LastByteRcvd - LastByteRead)
发送方还能发送的窗口大小
EffectiveWindow = AdvertisedWindow - (LastByteSent - LastByteAcked)
滑动窗口图示
发送方
接收方
流量控制
滑动窗口机制能防止发送方无脑的发送数据,导致接收方缓冲区被填满而无法接收新的数据。
如果一直无脑的发数据给对方,但对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪费。
可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是所谓的流量控制。
下面举个栗子,为了简单起见,假设以下场景:
客户端是接收方,服务端是发送方。
假设接收窗口和发送窗口相同,都为200,且在整个传输过程中都保持相同的窗口大小,不受外界影响。
根据上图的流量控制,说明下每个过程:
- 客户端向服务端发送请求数据报文。这里要说明下,本次例子是把服务端作为发送方,所以没有画出服务端的接收窗口。
- 服务端收到请求报文后,发送确认报文和80字节的数据,于是可用窗口 Usable减少为120字节,同时SND.NXT指针也向右偏移80字节后,指向321,这意味着下次发送数据的时候,序列号是321。
- 客户端收到80字节数据后,于是接收窗口往右移动80字节,RCV.NXT也就指向321,这意味着客户端期望的下一个报文的序列号是321,接着发送确认报文给服务端。
- 服务端再次发送了120字节数据,于是可用窗口耗尽为0,服务端无法在继续发送数据。
- 客户端收到120字节的数据后,于是接收窗口往右移动120字节,RCV.NXT 也就指向441,接着发送确认报文给服务端。
- 服务端收到对80字节数据的确认报文后,SND.UNA指针往右偏移后指向321,于是可用窗口Usable增大到80。
- 服务端收到对120字节数据的确认报文后,SND.UNA指针往右偏移后指向441,于是可用窗口Usable增大到 200。
- 服务端可以继续发送了,于是发送了160字节的数据后,SND.NXT指向601,于是可用窗口Usable减少到40。
- 客户端收到160字节后,接收窗口往右移动了160字节,RCV.NXT也就是指向了601,接着发送确认报文给服务端。
- 服务端收到对160字节数据的确认报文后,发送窗口往右移动了160字节,于是SND.UNA指针偏移了160后指向601,可用窗口Usable也就增大至了200。
死锁问题
引起死锁的原因
接收方在发送确认报文时可能会出现还能接收的窗口大小为零的情况,当发送rwnd=0的确认报文后不久,接收方的接收缓存因为读取了部分数据而又有了一些存储空间。于是接收方会发rwnd>0的报文段,然而这个报文段在传送中丢失了。此时,发送方会一直等待收到接收方发送的非零窗口的通知,而接收方也一直等待发送方发送的数据,就产生死锁了。
解决死锁的机制
TCP为每个连接设有一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器,若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带1字节的数据),而对方就在确认这个探测报文段时给出当前的窗口值。