TCP

TCP

TCP是一个全双工的运行在传输层的可靠传输协议。

为了防止网络的拥塞现象,TCP提出了一系列的拥塞控制机制。最初由V. Jacobson在1988年的论文中提出的TCP的拥塞控制由“慢启动(Slow start)”和“拥塞避免(Congestion avoidance)”组成,后来TCP Reno版本中又针对性的加入了“快速重传(Fast retransmit)”、“快速恢复(Fast Recovery)”算法。TCP的拥塞控制主要原理依赖于一个拥塞窗口(cwnd)来控制

除此之外,TCP还有一个对端通告的接收窗口(rwnd)用于流量控制。

报文格式

TCP_第1张图片

源端口和目的端口

一个IP地址和端口的组合称为“套接字”或“端点”。

所以IP协议中的源IP地址和目的地址

和TCP协议中的源端口和目的端口,

组成了“一对”套接字(发送端的套接字和接收端的套接字)。

序列号

每一个“TCP报文段中的第一个字节”都会被赋予一个序列号。

序列号是个32位数,到达2^32-1后会再回到0.

确认号(TCP返回报文使用)

也称ACK号或ACK字段。

确认号包含的值为:“确认号的发送方”希望接收的下一个序列号。(即最后接收成功的序列号+1)

 

  1. 三次握手和四次挥手的时候,序列号和确认号被用于通信报文中

  2. 发送数据时:第一个包的序列号是一个随机数。为了便于理解,这里就把它称为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号)。

窗口中的分组数量称之为:“窗口大小”。

下图为发送方的窗口以及其他分组队列:

TCP_第2张图片

如图所示,如果发送方下一步接收到了序列号为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_第3张图片

流量控制

滑动窗口实现了TCP流控制。首先明确滑动窗口的范畴:TCP是双工的协议,会话的双方都可以同时接收和发送数据。TCP会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。

滑动窗口解决的是流量控制的的问题,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致。接收端的缓存传输数据给应用层,但这个过程不一定是即时的,如果发送速度太快,会出现接收端数据overflow,流量控制解决的是这个问题。

滑动窗口

发送方的发送缓存内的数据都可以被分为4类:

  1. 已发送,已收到ACK

  2. 已发送,未收到ACK

  3. 未发送,但允许发送

  4. 未发送,但不允许发送

其中类型2和3都属于发送窗口。

接收方的缓存数据分为3类:

  1. 已接收

  2. 未接收但准备接收

  3. 未接收而且不准备接收

其中类型2属于接收窗口。

窗口大小代表了设备一次能从对端处理多少数据,之后再传给应用层。缓存传给应用层的数据不能是乱序的,窗口机制保证了这一点。现实中,应用层可能无法立刻从缓存中读取数据。

滑动机制

  1. 发送窗口只有收到发送窗口内字节的ACK确认,才会移动发送窗口的左边界。

  2. 发送端口的左边界为接收窗口ACK确认的最大一个包。

  3. 接收窗口只有在前面所有的段都确认的情况下才会移动左边界。当在前面还有字节未接收但收到后面字节的情况下,窗口不会移动,并不对后续字节确认。每收到一个后面的包,接收端会连续重复发送最大一个确认的ACK

  4. 发送端收到3个以上的ACK包,则会重传窗口中所有的报文

     

一个动画模拟流量控制过程的网址:动画的地址 该网址的模拟非常详细。

 

TCP套接字编程

TCP_第4张图片

 

总结

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

你可能感兴趣的:(网络相关,TCP)