快速重传

  通常当一个数据包丢失后,会发生连续重传,重传次数由tcp_retries2参数控制(默认为15);超时时间(Retransmission TimeOut)RTO进行相关计算,由于上述的过程比较漫长,所以当发送端连续收到3个或以上重复ACK时,会马上进行重传,称之为快速重传。
  我们将一个数据包切分为5段[0,1][1,2][2,3][3,4][4,5];当第一段[0,1]发出时回复ACK = 1;表示1之前的数据包都收到了,然后[1,2]发生丢包,后续的[2,3][3,4][4,5]正常接收,但是其回复的ACK仍然是2(表示2之前的包都收到了),如果后续收到姗姗来迟的[1,2]时则回复ACK =5(表示5之前的包都收到了);当发送端连续收到3个2时,就会马上重传

Q1:快重传示例中[1,2]包为啥回复ACK,其它段数据怎么知道是否到达?
A1:TCP头部字段中有个SACK,其中记录的就是[1,2]段后续的连续段区间,比如[2,3]包ACK =1,SACK = [0,1] [2,3](表示2-3号包都收到了);[3,4]包ACK =1,SACK = [0,1][2,4](表示2-4号包都收到了)

滑动窗口

  发送端发送数据时首先会将数据放入发送缓冲区,同理接收端会将需要接收的数据先放入接收缓冲区;当接收缓冲区中数据满了之后,数据会被丢弃,这时发送端应该停止继续发送数据。
  TCP的流量控制就是动态的调配发送端和接收端两个缓冲区的大小,我们将发送端的称为发送窗口,接收端的称为接收窗口,接收端在每次回复ACK时会携带当前接收窗口的可用大小,然后发送端根据这个大小动态调整自己发送窗口的大小;我们所说的流量控制一般是在发送端进行控制。
  通常情况下数据被分为一下几种类型
发送窗口:发送端所能发送的最大数据包大小,即包括在途数据包和可发送数据包大小
可用窗口:是即将发送的数据包大小;当可用窗口大小减小到0时,除非接收到ACK否则不会再发送数据

拥塞控制

拥塞窗口(cwnd):表示发送端在还未收到对端 ACK 之前还能发送的数据量大小,linux中通过initcwnd(默认值10)参数控制初始窗口大小;size(cwnd) = min(size(rwnd),size(cwnd));

慢启动

  当我们开始发送数据给对端时,不晓得对端的接收能力,如果以最快速的方式传输数据,很可能会因为对端的接收处理能力不足,造成频繁的丢包以及无限制的重传以至最后导致网络雪崩;所以我们使用拥塞窗口限制,开始使用initcwnd大小的窗口发送数据,后续cwnd在不丢包的情况下逐渐增加,这种机制我们成为慢启动
  cwnd的增长模式是每收到一个ACK:cwnd = cwnd+1;每经过一个RTT:cwnd = cwnd * 2

拥塞避免

  如果随着慢启动中cwnd那种模式增长下去,会造成失控,因此需要限制其无限制的增长,通过一个叫做慢启动阈值(ssthresh)控制其增长趋势;
  当cwnd < ssthresh,成指数级增长;
  当cwnd > ssthresh,成线性增长,即每经过一个RTT:cwnd= cwnd+1,无论期间受到多少个ACK

快速恢复

当连续收到3个重复ACK时:

  • 拥塞阈值 ssthresh 降低为 cwnd 的一半:ssthresh = cwnd / 2
  • 拥塞窗口 cwnd 设置为 ssthresh
  • 拥塞窗口线性增加