TCP的一个关键部分就是拥塞控制机制,因为IP层不向端系统提供显式的网络拥塞反馈,因此TCP必须使用端到端拥塞控制而不是使用网络辅助的拥塞控制。TCP Reno 就是广受赞誉的TCP拥塞控制算法,该算法主要由三部分组成:
1.慢启动;2. 拥塞避免;3.快速回复。
慢启动和拥塞避免是TCP的强制部分,两者的差异在于对收到的ACK做出反应时增加cwnd长度的方式,我们会发现慢启动比拥塞避免更快地增加cwnd的长度,快速回复为推荐部分,对TCP发送方并非是必需的。
1.慢启动
慢启动是建立TCP连接后,采用的第一个调整发送速率的算法(模式)。在这个阶段,cwnd通常被初始化为1MSS(Maximum Segment Size),用于对TCP发送方而言,可用带宽可能比MSS/RTT大的多,慢启动的目的就是尽快找到上限。
在慢启动阶段,发送方每接收到一个确认报文,就会将cwnd增加1MSS的大小,于是其情况就为:
- 初始cwnd=1MSS,所以可发送一个TCP最大报文段,成功确认后,cwnd = 2MSS;
- 此时可发送两个TCP最大报文段,成功接收后,cwnd = 4 MSS;
- 此时可发送四个TCP最大报文段,成功接收后,cwnd = 8 MSS ……
由于TCP是一次性将窗口内的所有报文发出,所以所有报文都到达并被确认的时间,近似的等于一个RTT。所以在这个阶段,拥塞窗口cwnd的长度将在每过一个RTT后,发送速率翻倍。因此TCP发送速率起始慢,但在慢启动发送速率将以指数级别增长。那在这个过程中何时结束这种指数增长,这又分几种情况:
- 第一种:若在慢启动的过程中,发生了数据传输超时(timeout),则此时TCP将ssthresh的值设置为cwnd / 2,然后将cwnd重新设置为1MSS,重新开始慢启动过程,这个过程可以理解为试探上限;
- 第二种:第一步试探出来的上限ssthresh将用在此处。若cwnd的值增加到>= ssthresh时,此时若继续使用慢启动的翻倍增长方式可能过于鲁莽,所以这个时候结束慢启动,改为拥塞避免模式;
- 第三种:若发送方接收到了某个报文的三次冗余ACK(即触发了快速重传的条件),则进入到快速恢复阶段;同时,ssthresh = cwnd / 2,然后cwnd = ssthresh + 3MSS;
2.拥塞避免
刚进入拥塞避免模式时,cwnd的大小近似的等于上次拥塞时的值的一半,即距离拥塞可能并不遥远。所以,拥塞避免是一个速率缓慢且线性增长的过程,在这个模式下,每经历一个RTT,cwnd的大小增加1MSS。也就是说,假设cwnd包含10个报文的大小,则每接收到一个确认报文,cwnd增加1/10 MSS,因此在收到对所有10个报文段的确认后,拥塞窗口的值将增加一个MSS。那在这个过程中何时结束这种线性增长,这又分几种情况:
- 第一种:在这个过程中,发生了超时,则表示网络拥塞,这时候,ssthresh被修改为cwnd / 2,然后cwnd被置为1MSS,并进入慢启动阶段;
- 第二种:若发送方接收到了某个报文的三次冗余ACK(即触发了快速重传的条件),此时也认为发生了拥塞, 则进入到快速恢复阶段;同时,ssthresh = cwnd / 2,然后cwnd = ssthresh + 3MSS;
3. 快速恢复
在快速恢复阶段,每接收到一个冗余的确认报文,cwnd就增加1MSS,其余不变,而当发生以下两种情况时, 将退出快速恢复模式:
- 第一种:在快速恢复过程中,计时器超时,那么ssthresh被修改为 cwnd / 2,然后cwnd被置为1MSS,并进入慢启动阶段;
- 第二种:若发送方接收到一条新的确认报文(不是冗余ACKS),则cwnd被置为ssthresh,然后进入到拥塞避免模式;
三种模式相互转换状态图
下面给出一张三种模式互相转换的状态图,途中箭头上的是转换的条件,条件有上下两部分,横线上方的是上面事件引起的转换,而下方是转换时发生的操作。
图为Reno拥塞控制状态机(状态图来源于计算机自顶向下书籍)
整个reno过程见下图: