TCP流量控制主要有四个知识点,慢启动、拥塞避免、快重传、快恢复。
其中慢启动和拥塞避免是用于拥塞控制的,是用来避免TCP在不确认带宽极限的情况下去慢慢地探测带宽的大小,首先先上图来初步认识下拥塞控制算法。
刚开始时TCP会先运行在慢启动状态下(cwnd(拥塞窗口)值为1,ssthresh为18,这个15其实也是一个懵出来的一个值)。
慢启动:
在慢重启的环境下,发送端每接收到接收端回复ACK,发送端就会把cwnd = cwnd * 2(当真实环境下确实有那么大量的包发的条件下),直到cwnd = ssthresh为止就会进入拥塞避免流程。
拥塞避免:
在拥塞避免的环境下,发送端每收到接收端回复ACK,发送端就会把cwnd = cwnd + 1直到发送端认为丢包为止,这里发送端通过两个方面认为丢包:(1) 连续收到三个包的确认ACK (2) 在超时时间内没有收到接收端的ACK。当丢包时发送端立刻把ssthresh = cwnd / 2,cwnd = 1立刻截流以免网络拥塞。
快速恢复:
由于出现丢包现象可能只是当前发送速率超过网络带宽了(连续收到三个重复ACK,说明网络状况还是挺好的^_^),因此不用一下子把发送速率降到最低,所以快恢复算法是把cwnd = cwnd / 2,然后进行拥塞避免流程。这样就不至于把连接的网速降的那么低。至于为什么在出现丢包的时候不把cwnd调整为拥塞前的值呢,这样最大只会用到整个网络带宽的3/4?!?这里我是这样想的,因为TCP是一个通用的网络传输协议,在一台机器里或者整个网络里不仅仅只有一个连接在使用网络而是有其他的连接也会使用到,因此单个连接不能独占整个网络的带宽,所以TCP需公平的均分网络的带宽而设计成这样的。
快速重传:
当发送端发送1,2,3,4,5包,然而接收端只收到1,2,4,5,这样接收端每收到比序号3大的包就会发序号2的ACK给发送端以表明丢包,而发送端连续收到3个序号3的ACK后就会立刻重发3~5的包。这里为什么不是只发序号3的包呢?我个人是这样认为的发送端知道了丢包后可能会觉得当前的网络有点糟糕了为保守起见我还是把序号3之后的包一起发,这样就避免了后续还有缺包的话就绪补发(可能也是懒之过^_^)