我们知道TCP是拥有拥塞控制机制的,而UDP是没有的,为什么需要拥塞控制机制呢,就是防止丢包过多导致传输效率低下。网络中传输的包太多,路由器的缓存又不够,每一个发送端都以自己想要的发送速率发送包,自然会导致网络拥塞。所以我TCP就包括了拥塞控制机制。
有几种拥塞控制方法?
2种
1.端到端拥塞控制。网络层没有显示的告知传输层此时网络出现拥塞了,传输层通过报文段的丢失(超时或3次冗余确认得知)认为网络出现拥塞了,TCP会缩减其拥塞窗口,减小发送速率。
2.网络辅助的拥塞控制。网络层显示的告知发送端此时网络拥塞了,少发点。
有两种告知方式:1.直接反馈信息可以由网络路由器发送给发送端,采用阻塞分组的形式。
2.路由器标记或更新从发送端向接收方的分组中的某个字段来指示拥塞产生。一旦受到一个标记的分组后,接收方就会向发送方通知该网络阻塞指示。
TCP采用的是第一种方式,也就是端到端的拥塞控制。
端到端拥塞控制机制的实现?
首先明确下,发生端会通过设置一个拥塞窗口(congestion window cwnd),有点像可靠性传输中的滑动窗口,维持窗口的大小,窗口越大代表你发送的速率越快,发送的字节越多。
其中有3种拥塞控制算法:慢启动( slow-start )、拥塞避免( congestion avoidance )、快重传( fast retransmit )和快速恢复( fast recovery )。
1.慢启动
当新建TCP连接时,cwnd初始化设为1个最大报文段(MSS)大小,发送端开始按照拥塞窗口大小发送数据,每当有一个报文段被确认,cwnd就增加1个MSS大小。这样cwnd的值就随着网络往返时间(Round Trip Time,RTT)呈指数级增长,事实上,慢启动的速度一点也不慢,只是它的起点比较低一点而已。我们可以简单计算下:
开始 ---> cwnd = 1
经过1个RTT后 ---> cwnd = 2*1 = 2
经过2个RTT后 ---> cwnd = 2*2= 4
经过3个RTT后 ---> cwnd = 4*2 = 8
由此可见慢启动的增长速度很快,cwnd也会指数增长,那你会不会有疑问,那这种指数增长啥时候停止呢?
有3中情况会让慢启动停止:
1.TCP使用了一个叫慢启动阀门值(ssthresh)的变量,当cwnd超过该值后,慢启动过程结束,进入拥塞避免阶段。对于大多数TCP实现来说,ssthresh的值是65536(同样以字节计算)。
2.超时丢包事件发生。TCP发送方将cwnd设置为1,慢启动阀门值(ssthresh)设置为cwnd/2,并重新开始慢启动过程。
3.检测到3个冗余的ACK。这时TCP执行一种快速重传并进入快速恢复状态。
2.拥塞避免
一旦进入到拥塞避免,则说明cwnd目前的值里拥塞可能并不遥远了,你就不应该使用慢启动那种指数增长的方式扩展cwnd,此时用的是较为保守的方式,每个RTT只是将cwnd的值增加1个MSS。
那什么时候结束拥塞避免呢?
1.出现超时丢包。cwnd值被设置为1个MSS大小,慢启动阀门值(ssthresh)被设置为cwnd/2。
2.3个冗余的ACK。不改变发送速率。
3.快速恢复
1.当收到3个冗余的ACK时,把ssthresh设置为cwnd的一半,把cwnd设置为ssthresh的值加3,然后重传丢失的报文段,加3的原因是因为收到3个重复的ACK,表明有3个“老”的数据包离开了网络。
2.再收到重复的ACK时,拥塞窗口增加1。
3.当收到新的数据包的ACK时,把cwnd设置为第一步中的ssthresh的值。原因是因为该ACK确认了新的数据,说明从重复ACK时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态。注意,如果在此过程出现超时,则重新进入慢启动阶段。