TCP是一个全双工的运行在传输层的可靠传输协议。
为了防止网络的拥塞现象,TCP提出了一系列的拥塞控制机制。最初由V. Jacobson在1988年的论文中提出的TCP的拥塞控制由“慢启动(Slow start)”和“拥塞避免(Congestion avoidance)”组成,后来TCP Reno版本中又针对性的加入了“快速重传(Fast retransmit)”、“快速恢复(Fast Recovery)”算法。TCP的拥塞控制主要原理依赖于一个拥塞窗口(cwnd)来控制
除此之外,TCP还有一个对端通告的接收窗口(rwnd)用于流量控制。
源端口和目的端口
一个IP地址和端口的组合称为“套接字”或“端点”。
所以IP协议中的源IP地址和目的地址
和TCP协议中的源端口和目的端口,
组成了“一对”套接字(发送端的套接字和接收端的套接字)。
序列号
每一个“TCP报文段中的第一个字节”都会被赋予一个序列号。
序列号是个32位数,到达2^32-1后会再回到0.
确认号(TCP返回报文使用)
也称ACK号或ACK字段。
确认号包含的值为:“确认号的发送方”希望接收的下一个序列号。(即最后接收成功的序列号+1)
三次握手和四次挥手的时候,序列号和确认号被用于通信报文中
发送数据时:第一个包的序列号是一个随机数。为了便于理解,这里就把它称为1号包。假定这个包的负载长度是100字节,那么可以推算出下一个包的序列号应该是101。
头部长度
该字段表示TCP头部的长度,以32位字为单位。
由于“选项字段”大小是可变的,所以“头部长度”字段是必须的。
TCP头部长度最大为60字节,如果没有选项字段,则为20个字节。
8种状态标识
以下各个标识表示了“该TCP报文段”是干什么的。
如:
SYN和ACK可能同时为1,它表示的就是建立连接之后的响应。
单个的一个SYN,它表示的只是建立连接。
1、CWR:拥塞窗口减(发送方降低它的发送速率)。
2、ECE:ECN回显(发送方接收到了一个更早的拥塞通告)
3、URG:紧急(紧急指针字段有效,很少用)
4、ACK:确认(确认号字段有效,连接建立后一般都是启用状态)
5、PSH:推送(几乎没被用到)
6、RST:重置连接(连接取消)
7、SYN:表示建立连接
8、FIN:该报文的发送方已经结束向对方发送数据
窗口大小
在TCP协议里,一个分组从发送端发送到接收端后,接收端应该返回一个ACK号。
如之前所说,每一个分组都是从“序列号”开始的,我们定一个术语“窗口”,来表示:已发送的分组们,但这些分组还未返回确认号(ACK号)。
窗口中的分组数量称之为:“窗口大小”。
下图为发送方的窗口以及其他分组队列:
如图所示,如果发送方下一步接收到了序列号为4的分组的“ACK”,则“窗口向右滑动一个分组”,意味着分组4可以释放了,分组7可以发送了。这种行为称之为:“窗口滑动协议”。
TCP校验和
该校验算法与IP、ICMP、UDP校验算法一致,其覆盖了TCP头部和数据中的一些字段。
紧急指针
只有在有URG字段时才有效。该指针是一个加到“序列号字段”上的正偏移,以产生“紧急数据”的最后一个字节的序列号。
选项
最常见的选项字段为:“最大段大小”字段,称为MSS。
连接的每个端点(套接字)一般在它发送的第一个报文段上指定该选项。
考虑拥塞的时候我们一般不考虑rwnd的值,只讨论如何确定cwnd值的大小。关于cwnd的单位,在TCP中是以字节来做单位的,我们假设TCP每次传输都是按照MSS大小来发送数据的,因此你可以认为cwnd按照数据包个数来做单位也可以理解,所以有时我们说cwnd增加1也就是相当于字节数增加1个MSS大小。
慢启动
最初的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
如果带宽为W,那么经过RTT*log2W时间就可以占满带宽。
拥塞避免
从慢启动可以看到,cwnd可以很快的增长上来,从而最大程度利用网络带宽资源,但是cwnd不能一直这样无限增长下去,一定需要某个限制。TCP使用了一个叫慢启动门限(ssthresh)的变量,当cwnd超过该值后,慢启动过程结束,进入拥塞避免阶段。对于大多数TCP实现来说,ssthresh的值是65536(同样以字节计算)。拥塞避免的主要思想是加法增大,也就是cwnd的值不再指数级往上升,开始加法增加。此时当窗口中所有的报文段都被确认时,cwnd的大小加1,cwnd的值就随着RTT开始线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。
上面讨论的两个机制都是没有检测到拥塞的情况下的行为,那么当发现拥塞了cwnd又该怎样去调整呢?
首先来看TCP是如何确定网络进入了拥塞状态的,TCP认为网络拥塞的主要依据是它重传了一个报文段。上面提到过,TCP对每一个报文段都有一个定时器,称为重传定时器(RTO),当RTO超时且还没有得到数据确认,那么TCP就会对该报文段进行重传,当发生超时时,那么出现拥塞的可能性就很大,某个报文段可能在网络中某处丢失,并且后续的报文段也没有了消息,在这种情况下,TCP反应比较“强烈”:
1.把ssthresh降低为cwnd值的一半
2.把cwnd重新设置为1
3.重新进入慢启动过程。
从整体上来讲,TCP拥塞控制窗口变化的原则是AIMD原则,即加法增大、乘法减小。可以看出TCP的该原则可以较好地保证流之间的公平性,因为一旦出现丢包,那么立即减半退避,可以给其他新建的流留有足够的空间,从而保证整个的公平性。
快速重传
那就是收到3个相同的ACK。TCP在收到乱序到达包时就会立即发送ACK,TCP利用3个相同的ACK来判定数据包的丢失,此时进行快速重传,快速重传做的事情有:
1.把ssthresh设置为cwnd的一半
2.把cwnd再设置为ssthresh的值(具体实现有些为ssthresh+3)
3.重新进入拥塞避免阶段。
快速恢复
后来的“快速恢复”算法是在上述的“快速重传”算法后添加的,当收到3个重复ACK时,TCP最后进入的不是拥塞避免阶段,而是快速恢复阶段。快速重传和快速恢复算法一般同时使用。快速恢复的思想是“数据包守恒”原则,即同一个时刻在网络中的数据包数量是恒定的,只有当“老”数据包离开了网络后,才能向网络中发送一个“新”的数据包,如果发送方收到一个重复的ACK,那么根据TCP的ACK机制就表明有一个数据包离开了网络,于是cwnd加1。如果能够严格按照该原则那么网络中很少会发生拥塞,事实上拥塞控制的目的也就在修正违反该原则的地方。
具体来说快速恢复的主要步骤是:
1.当收到3个重复ACK时,把ssthresh设置为cwnd的一半,把cwnd设置为ssthresh的值加3,然后重传丢失的报文段,加3的原因是因为收到3个重复的ACK,表明有3个“老”的数据包离开了网络。
2.再收到重复的ACK时,拥塞窗口增加1。
3.当收到新的数据包的ACK时,把cwnd设置为第一步中的ssthresh的值。原因是因为该ACK确认了新的数据,说明从重复ACK时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态。
具体的过程可以参考:
滑动窗口实现了TCP流控制。首先明确滑动窗口的范畴:TCP是双工的协议,会话的双方都可以同时接收和发送数据。TCP会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。
滑动窗口解决的是流量控制的的问题,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致。接收端的缓存传输数据给应用层,但这个过程不一定是即时的,如果发送速度太快,会出现接收端数据overflow,流量控制解决的是这个问题。
滑动窗口
发送方的发送缓存内的数据都可以被分为4类:
已发送,已收到ACK
已发送,未收到ACK
未发送,但允许发送
未发送,但不允许发送
其中类型2和3都属于发送窗口。
接收方的缓存数据分为3类:
已接收
未接收但准备接收
未接收而且不准备接收
其中类型2属于接收窗口。
窗口大小代表了设备一次能从对端处理多少数据,之后再传给应用层。缓存传给应用层的数据不能是乱序的,窗口机制保证了这一点。现实中,应用层可能无法立刻从缓存中读取数据。
滑动机制
发送窗口只有收到发送窗口内字节的ACK确认,才会移动发送窗口的左边界。
发送端口的左边界为接收窗口ACK确认的最大一个包。
接收窗口只有在前面所有的段都确认的情况下才会移动左边界。当在前面还有字节未接收但收到后面字节的情况下,窗口不会移动,并不对后续字节确认。每收到一个后面的包,接收端会连续重复发送最大一个确认的ACK
发送端收到3个以上的ACK包,则会重传窗口中所有的报文
一个动画模拟流量控制过程的网址:动画的地址 该网址的模拟非常详细。
TCP的拥塞控制算法就是要在cwnd和rwnd两者之间权衡,选取最好的cwnd值,从而使得网络吞吐量最大化且不产生拥塞。
接收方根据自己的接收能力设定了接收窗口rwnd,并把这个窗口值写入TCP首部中的窗口字段,传送给发送方。因此,接收窗口又称为通知窗口。因此,从接收方对发送方的流量控制的角度考虑,发送方的发送窗口一定不能超过对方给出的接收窗口rwnd 。
发送方窗口的上限值 = Min [ rwnd, cwnd ]
当rwnd < cwnd 时,是接收方的接收能力限制发送方窗口的最大值。
当cwnd < rwnd 时,则是网络的拥塞限制发送方窗口的最大值。
TCP连接过程:
TCP三次握手与四次挥手
参考:
https://www.cnblogs.com/red-code/p/8394892.html
https://blog.csdn.net/itmacar/article/details/12278769
https://blog.csdn.net/yao5hed/article/details/81046945