TCP重传与拥塞控制机制一览

开源Linux

共 3926字,需浏览 8分钟

 ·

2022-11-01 17:16

目录

  • 重传机制

  • 超时重传

  • 快速重传

  • SACK 方法

  • Duplicate SACK

  • 滑动窗口

  • 窗口大小

  • 接收窗口

  • 发送窗口

  • 拥塞控制

  • 慢启动

  • 拥塞避免

  • 拥塞发生

  • 为何快速重传是选择3次ACK?

  • 快速恢复

重传机制


重传机制一般是用来解决数据包在错综复杂的网络中丢失的情况。


常见的重传机制:

超时重传

快速重传

SACK

D-SACK


超时重传


重传机制的其中一个方式,就是在发送数据时,设定一个定时器。


当超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据,也就是我们常说的超时重传


TCP 会在以下两种情况发生超时重传:

数据包丢失

确认应答丢失



超时时间应该设置为多少呢?

超时重传时间 RTO 的值应该略大于报文往返 RTT 的值


RTT 指的是数据发送时刻到接收到确认的时刻的差值,也就是包的往返时间。


超时重传时间是以 RTO (Retransmission Timeout 超时重传时间)表示。





如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍。


也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。


快速重传


快速重传

TCP 还有另外一种快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传。




快速重传机制只解决了一个问题,就是超时时间的问题,但是它依然面临着另外一个问题。就是重传的时候,是重传之前的一个,还是重传所有的问题。


为了解决不知道该重传哪些 TCP 报文,于是就有 SACK 方法。


SACK 方法


还有一种实现重传机制的方式叫:SACK( Selective Acknowledgment 选择性确认)。


这种方式需要在 TCP 头部「选项」字段里加一个 SACK 的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据


Duplicate SACK


Duplicate SACK 又称 D-SACK,其主要使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。


滑动窗口


滑动窗口是为了提升通信效率在操作系统开辟的一个缓存空间,发送方主机在等到确认应答返回之前,必须在缓冲区中保留已发送的数据。如果按期收到确认应答,此时数据就可以从缓存区清除。


TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。


TCP会话的双方都各自维护一个发送窗口和一个接收窗口。接收窗口大小取决于应用、系统、硬件的限制。发送窗口则取决于对端通告的接收窗口。


接收方发送的确认报文中的window字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将接收方的确认报文window字段设置为 0,则发送方不能发送数据。


TCP头包含window字段,16bit位,它代表的是窗口的字节容量,最大为65535。这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。接收窗口的大小是约等于发送窗口的大小。


窗口大小


窗口大小由哪一方决定?


TCP 头里有一个字段叫 Window,也就是窗口大小。


这个字段是接收方告诉发送端子机还有多少缓冲区可以接收数据的。


发送端会根据反馈回来的信息发送数据,这样就可以保证不会出现接收端处理不过来的情况。


这其实就是流量控制。


流量控制是TCP 提供的一种可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量的一种机制。


接收窗口



#1 是已发送并收到 ACK确认的数据:1~31 字节

#2 是已发送但未收到 ACK确认的数据:32~45 字节

#3 是未发送但总大小在接收方处理范围内(接收方还有空间):46~51字节

#4 是未发送但总大小超过接收方处理范围(接收方没有空间):52字节以后


程序是如何表示发送方的四个部分的呢?

TCP 滑动窗口方案使用三个指针来跟踪在四个传输类别中的每一个类别中的字节。

其中两个指针是绝对指针(指特定的序列号),一个是相对指针(需要做偏移)。

SND.WND:表示发送窗口的大小(大小是由接收方指定的);

SND.UNA(Send Unacknoleged):是一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号,也就是 #2 的第一个字节。

SND.NXT:也是一个绝对指针,它指向未发送但可发送范围的第一个字节的序列号,也就是 #3 的第一个字节。

指向 #4 的第一个字节是个相对指针,它需要 SND.UNA 指针加上 SND.WND 大小的偏移量,就可以指向 #4 的第一个字节了。


发送窗口




#1 + #2 是已成功接收并确认的数据(等待应用进程读取);

#3 是未收到数据但可以接收的数据;

#4 未收到数据并不可以接收的数据;

其中三个接收部分,使用两个指针进行划分:


RCV.WND:表示接收窗口的大小,它会通告给发送方。

RCV.NXT:是一个指针,它指向期望从发送方发送来的下一个数据字节的序列号,也就是 #3 的第一个字节。

指向 #4 的第一个字节是个相对指针,它需要 RCV.NXT 指针加上 RCV.WND 大小的偏移量,就可以指向 #4 的第一个字节了。


接收窗口和发送窗口的大小是相等的吗?

并不是完全相等,接收窗口的大小是约等于发送窗口的大小的。

因为接收窗口的大小是由 TCP报文中的 Windows 字段来告诉发送方的,而这个传输过程是存在实验的,所以接收窗口和发送窗口是约等于的关系。


拥塞控制


为什么要有拥塞控制呀,不是有流量控制了吗?

流量控制确实避免了「发送方」的数据填满「接收方」的缓存,但是机制并不知道网络的中发生了什么。

网络中对资源需求超过了资源可用量的情况就叫做拥塞。

如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。


流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。


拥塞控制主要是四个算法:

慢启动

拥塞避免

拥塞发生

快速恢复


拥塞窗口:为了调节发送方所要发送数据的量而引入的概念


发送窗口 swnd 和接收窗口 rwnd 是约等于的关系


加入了拥塞窗口的概念后,此时发送窗口的值是swnd = min(cwnd, rwnd),


拥塞窗口 cwnd 变化的规则:

只要网络中没有出现拥塞,cwnd 就会增大;

但网络中出现了拥塞,cwnd 就减少;


慢启动


机制含义:TCP 在刚建立连接完成后,缓慢提高发送数据包的数量


算法机制:当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1。


有一个叫慢启动门限 ssthresh (slow start threshold)状态变量。


当 cwnd < ssthresh 时,使用慢启动算法。

当 cwnd >= ssthresh 时,就会使用「拥塞避免算法」。


拥塞避免


算法机制:每当收到一个 ACK 时,cwnd 增加 1/cwnd。



如图,拥塞避免算法就是将原本慢启动算法的指数增长变成了线性增长,还是增长阶段,但是增长速度缓慢了一些。


就这么一直增长着后,网络就会慢慢进入了拥塞的状况了,于是就会出现丢包现象,这时就需要对丢失的数据包进行重传。


当触发了重传机制,也就进入了「拥塞发生算法」。


拥塞发生


TCP拥塞控制默认认为网络丢包是由于网络拥塞导致的,,所以一般的TCP拥塞控制算法以丢包为网络进入拥塞状态的信号。


对于丢包有两种判定方式:

超时重传

快速重传


超时重传:是TCP协议保证数据可靠性的一个重要机制,其原理是在发送一个数据以后就开启一个计时器,在一定时间内如果没有得到发送数据报的ACK报文,那么就重新发送数据,直到发送成功为止。


当 RTO超时后,TCP会重传 数据包并做出以下反映。


将慢启动的阈值设置为 当前 cwnd 的一半

cwnd 重置为一

进入慢启动过程


快速重传:当发送端接收到3个以上的重复ACK,TCP就意识到数据发生丢失,需要快速重传。


快速重传后不会使用慢启动算法,而是直接使用拥塞避免算法。所以也叫快速恢复算法Fast Recovery。


cwnd大小缩小为当前的一半

将慢启动的阈值设置为为缩小后的cwnd大小

然后进入快速恢复算法Fast Recovery。


为何快速重传是选择3次ACK?

两次duplicated ACK时很可能是乱序造成的!三次duplicated ACK时很可能是丢包造成的!四次duplicated ACK更更更可能是丢包造成的,但是这样的响应策略太慢。丢包肯定会造成三次duplicated ACK!综上是选择收到三个重复确认时窗口减半效果最好,这是实践经验。


快速恢复


快速重传和快速恢复算法一般同时使用,快速恢复算法是认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈。


然后,进入快速恢复算法如下:


拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);

重传丢失的数据包;

如果再收到重复的 ACK,那么 cwnd 增加 1;

如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;



关于TCP的总结就到这里啦,你弄懂了吗?

本文节选自:小林coding

Linux学习指南

有收获,点个在看 

浏览 14
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报