面经-如何保证tcp实现可靠储传输

185 阅读6分钟

4.2 TCP 重传、滑动窗口、流量控制、拥塞控制 | 小林coding (xiaolincoding.com)

3.webp

重传机制

TCP 实现可靠传输的方式之一,是通过序列号与确认应答。

4.webp

一旦数据丢失就要重传:

image.png

超时重传

重传机制的其中一个方式,就是在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据,也就是我们常说的超时重传

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

7.webp

8.webp

快速重连

快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传

10.webp

在上图,发送方发出了 1,2,3,4,5 份数据:

  • 第一份 Seq1 先送到了,于是就 Ack 回 2;
  • 结果 Seq2 因为某些原因没收到,Seq3 到达了,于是还是 Ack 回 2;
  • 后面的 Seq4 和 Seq5 都到了,但还是 Ack 回 2,因为 Seq2 还是没有收到;
  • 发送端收到了三个 Ack = 2 的确认,知道了 Seq2 还没有收到,就会在定时器过期之前,重传丢失的 Seq2。
  • 最后,收到了 Seq2,此时因为 Seq3,Seq4,Seq5 都收到了,于是 Ack 回 6 。

所以,快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。

SACK- 解决上面两个传输同时丢失的情况

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

11.webp

D-SACK

  • 使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。
  • ACK丢失,发送方以为没发成功就一直发,超时重发,但是返回的ack为4000,意味着丢包

12.webp

滑动窗口 -- 避免相应等待

窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值

image.png

图中的 ACK 600 确认应答报文丢失,也没关系,因为可以通过下一个确认应答进行确认,只要发送方收到了 ACK 700 确认应答,就意味着 700 之前的所有数据「接收方」都收到了。这个模式就叫累计确认或者累计应答

流量控制 -- 不能无脑发送

让「发送方」根据「接收方」的实际接收能力控制发送的数据量,这就是所谓的流量控制。

由滑动窗口协议(连续ARQ协议)实现。

例子:

22.webp

image.png

在前面我们都看到了,TCP 通过让接收方指明希望从发送方接收的数据大小(窗口大小)来进行流量控制。

窗口关闭

如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。

但如果窗口关闭后,接受方处理完数据窗口增大了,于是想通知发送方我的窗口变大了,但是这个ACK报文丢失,那么就会进入死锁状态

24.webp

为了解决死锁呢,tcp为每个连接设置一个持续定时器,只要tcp连接一方收到0窗口通知,就打开持续计时器,如果超时,就发送窗口探测报文,对方收到会给出自己现在窗口的大小。如果几次探测之后还是0,那么tcp会中断连接

糊涂窗口综合症

如果接收方太忙了,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。

到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症

25.webp 接收方通常的策略如下:

当「窗口大小」小于 min( MSS,缓存空间/2 ) ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为 0,也就阻止了发送方再发数据过来。

等到接收方处理了一些数据后,窗口大小 >= MSS,或者接收方缓存空间有一半可以使用,就可以把窗口打开让发送方发送数据过来。

发送方通常的策略:

使用 Nagle 算法,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据:

  • 要等到窗口大小 >= MSS 或是 数据大小 >= MSS
  • 收到之前发送数据的 ack 回包

拥塞控制

  • 拥塞控制针对网络,不针对接收方。避免「发送方」的数据填满整个网络。
  • 发送窗口的值是swnd = min(cwnd, rwnd),

image.png 拥塞窗口 cwnd是发送方维护的一个的状态变量,它会根据网络的拥塞程度动态变化的

image.png

慢启动

这个慢启动的意思就是一点一点的提高发送数据包的数量,如果一上来就发大量的数据,这不是给网络添堵吗?当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1。

27.webp

设置一个阈值当cwnd<阈值的时候,执行慢启动 ,当cwnd>阈值的时候执行拥塞避免算法

拥塞避免算法

每当收到一个 ACK 时,cwnd 增加 1/cwnd。

28.webp

但是一直增加也会发生拥塞丢包,需要重传,进入拥塞发生算法」

拥塞发生算法

image.png

image.png

快速恢复

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

正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了:

  • cwnd = cwnd/2 ,也就是设置为原来的一半;
  • ssthresh = cwnd;

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

  • 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);
  • 重传丢失的数据包;
  • 如果再收到重复的 ACK,那么 cwnd 增加 1;
  • 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;