TCP 协议重传机制


# TCP 协议重传机制

TCP 协议是一种可靠的,面向连接的,基于字节流的传输协议。既然是一种可靠的传输协议,那么必须有一种机制来保证接收方收到的数据是完整地,这就是 TCP 协议的重传机制。

# 常见包传输问题

假如要传输一个大小为 1M 的数据包,由于最大传输单元(MTU)的限制,需要将包拆分为 N 个小包进行传输,并且对每一个包进行编号,这里假如这个 N 为 200,那么编号就为 1,2,3,4 ..... 198,199,200。

发送方按照编号顺序 Seq=1,2,3,4,5 .... 200 发送给接收方,接收方收到包后需要给接收方发送 ACK=2,3,4,5,6 .... 201 的确认包,接收方将所有包接收完成之后则进行数据拼接,完成一次传输。

由于网络环境的复杂性,这里会涉及到包乱序重复丢包问题。

# 乱序

发送方按照序号 Seq=1,2,3,4,5 的顺序发包,接收方收到的包可能是 1,2,4,3,5。

解决方案:接收方发现先收到了序号为 4 的包,那么会将编号为 4 的包先缓存起来,等收到了编号为 3 的包后再将他们按顺序进行排列。

# 丢包

发送方按照序号 Seq=1,2,3,4,5 的顺序发包,接收方收到的包可能是 1,2,3,5。

解决方案:接收方发现先收到了编号为 5 的包,但是编号为 4 的包迟迟没有收到,那么这里会触发重传机制,让接收方知道,编号为 4 的包丢掉了,需要重新发,这里的重传机制在下面细讲。

# 重复包

由于包在网络层有延迟等触发 TCP 重传,接收方收到的包可能是 1,2,3,3,4,5。

解决方案:接收方发现收到的编号为 3 的包已经存在了,那么在此收到编号为 3 的包,它也不会进行处理,直接丢弃。

# TCP 的重传机制

TCP 提供两种重传的机制,一种是基于时间的超时重传,一种是基于接收端反馈消息的快速重传。相比之下前者占用更少的网络带宽,但是效率很低。而后者则相反

# 超时重传机制

顾名思义,即基于计时器的重传。简单来讲,超时重传就是发送方设置一个超时时间,如果在这个时间内未收到接收方的 ACK 确认应答,那么发送方即对包进行重发。

超时时间一般设置的都比较简单,比如 200ms,但是现实中网络环境比较复杂,快一点的传输耗时 50ms,这种情况下用 200ms 来判断超时传输效率会有些低;假设你访问某国外网站,延迟有 130 ms,这就麻烦了,正常的数据包都可能被认为是超时,导致大量数据包被重发,可以想象,重发的数据包也很容易被误判为超时,所以设置固定值是很不可靠的,我们要根据网络延迟,动态调整超时时间,延迟越大,超时时间越长。

在这里先引入两个概念:

  • RTT(Round Trip Time):往返时延,也就是数据包从发出去到收到对应 ACK 的时间。RTT 是针对连接的,每一个连接都有各自独立的 RTT。
  • RTO(Retransmission Time Out):重传超时,也就是前面说的超时时间。

这种机制下,每个数据包都有相应的计时器,一旦超过 RTO 而没有收到 ACK,就重发该数据包。没收到 ACK 的数据包都会存在重传缓冲区里,等到 ACK 后,就从缓冲区里删除。

首先明确一点,对 TCP 来说,超时重传是相当重要的事件(RTO 往往大于两倍的 RTT,超时往往意味着拥塞),一旦发生这种情况,TCP 不仅会重传对应数据段,还会降低当前的数据发送速率,因为 TCP 会认为当前网络发生了拥塞。

# 快速重传机制

快速重传机制基于接收端的反馈信息来引发重传,而非重传计时器超时。

刚刚提到过,基于计时器的重传往往要等待很长时间,而快速重传使用了很巧妙的方法来解决这个问题:服务器如果收到乱序的包,也给客户端回复 ACK,只不过是重复的 ACK。

还是拿前面的例子来说,收到乱序的包 6,7,8,9 时,服务器全都发 ACK = 5。这样,客户端就知道 5 发生了空缺。一般来说,如果客户端连续三次收到重复的 ACK,就会重传对应包,而不需要等到计时器超时。

(完)