流量控制
如果发送方发送数据过快,那么接收方来不及接收,就会丢弃数据。为了避免分组丢失,需要进行流量控制,避免发送方的数据将接收方淹没。
实现
流量控制的实现是基于滑动窗口。接收方在发送给发送方的ACK中包含了自己的接收窗口大小,当接收窗口为0时,发送方将暂停发送数据。
例如下图中,在连接建立时,发送方B告知接收方A,它的接收窗口大小为400,那么发送方发送的数据不能超过这个大小。
Nagle算法
此算法主要是为了避免发送方频繁地向接收方发送较小的数据。如果发送方发送1字节的数据,每次发送的IP包大小为20 + 20 + 1,分别是IP头部 + TCP头部 + 数据,这样会造成带宽的浪费。
Nagle算法流程
- 发送方先发送1字节的数据
- 对于后面需要发送的数据,发送方会先缓存起来
- 当收到前一个发送数据的ACK时,才发送缓存的数据
- 若缓存的数据达到发送窗口的一半或者达到报文段的最大长度,也会发送数据
愚笨窗口综合症(silly window syndrome)
此算法主要是为了避免接收方频繁地向发送方发送ACK。当接收方的接收窗口满时,应用层每次从接收窗口读取1字节的数据,此时接口方立即向发送方发送ACK,告知发送方此时接收窗口为1,可以发送1字节的数据,那么发送方不得不发送1字节的数据,此时接收窗口又满了。如此反复使得传输效率低下
为了避免上述情况,接收方需要等待一段时间,当接收窗口有一半空闲的大小或者可以容纳一个最长的报文,则发送ACK到发送方,告知其接收窗口大小。
拥塞控制
路由器有一个数据队列,用来保存接收到的数据,当路由器接收到太多的数据,导致队列满了,就会无条件地丢弃新到来的数据。此时上层的TCP认为数据在网络中丢失了,又会重传这些数据,而路由器又会丢弃这些重传的数据,如此反复,导致网络性能下降。因此TCP需要进行拥塞控制
流量控制与拥塞控制的区别
拥塞控制是防止过多的数据涌入到网络中,它是一个全局性的过程,它涉及到所有主机,所有的路由器。
流量控制针对的是点对点之间的通信,它主要是防止接收方被发送方的数据淹没,即控制发送方发送数据的速率,使得接收方来得及接收。
拥塞算法
TCP通过拥塞窗口(cwnd)来控制拥塞,发送方可以发送的数据大小为,其中rwnd表示接收窗口
min(cwnd,rwnd)
在不同的阶段,cwnd具有不同的计算方式
慢启动阶段(Slow Start Phase)
在慢启动阶段,初始时,cwnd被设置为1,但是每经过一个RTT,cwnd变成指数增长,直到cwnd>=阈值(ssthresh)
Initially cwnd = 1
After 1 RTT, cwnd = 2^(1) = 2
2 RTT, cwnd = 2^(2) = 4
3 RTT, cwnd = 2^(3) = 8
拥塞避免阶段(Congestion Avoidance Phase)
当cwnd>=ssthresh,进入拥塞避免阶段。因为此时网络拥塞的可能性变大,cwnd不在指数增长,而变成线性增长,每经过一个RTT,cwnd = cwnd + 1
Initially cwnd = i
After 1 RTT, cwnd = i+1
2 RTT, cwnd = i+2
3 RTT, cwnd = i+3
拥塞检测阶段(Congestion Detection Phase)
当网络出现拥塞时,TCP需要判断是什么情况导致了拥塞,对于不同的情况,cwnd的计算不同。
(1)由于超时而导致的重传
1. ssthresh变成cwnd的一半,ssthresh=cwnd/2
2. cwnd重置为1
3. 进入到慢启动阶段
如上图所示,当cwnd=24时,发生超时,ssthresh被重置为cwnd的一半,即ssthresh=cwnd/2=12.同时cwnd被重置为1,再次进入慢启动阶段
(2) 连续收到3个重复的ACK(数据丢失了)
1. ssthresh变成cwnd的一半,ssthresh=cwnd/2
2. cwnd重置为ssthresh
3. 进入到拥塞避免阶段
如上图,当收到3个重复的ACK,ssthresh被重置为cwnd的一半,即ssthresh=cwnd/2=12,同时cwnd被重置为ssthresh,即12,同时开始进入拥塞检测阶段,cwnd开始线性增长。