TCP 实现可靠传输的方式之一,是通过序列号与确认应答。在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个确认应答消息,表示已收到消息。

但在错综复杂的网络,并不一定能如上图那么顺利能正常的数据传输,万一数据在传输过程中丢失了呢? 所以 TCP 针对数据包丢失的情况,会用重传机制解决。接下来说说常⻅的重传机制:

  • 超时重传
  • 快速重传
  • SACK
  • D-SACK

    超时重传

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

  • 数据包丢失

  • 确认应答丢失

image.png

快速重传

TCP 还有另外一种快速重传(Fast Retransmit)机制,它不以时间为驱动,而是以数据驱动重传
image.png
在上图,发送方发出了 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方法

还有一种实现重传机制的方式叫: SACK ( Selective Acknowledgment 选择性确认)。
这种方式需要在 TCP 头部「选项」字段里加一个 SACK 的东⻄,它可以将缓存的地图发送给发送方,这样发送 方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据

如下图,发送方收到了三次同样的 ACK 确认报文,于是就会触发快速􏰀发机制,通过 SACK 信息发现只有 200~299 这段数据丢失,则􏰀发时,就只选择了这个 TCP 段进行重复。
image.png
如果要支持 SACK ,必须双方都要支持。在 Linux 下,可以通过 net.ipv4.tcp_sack 参数打开这个功能(Linux 2.4 后默认打开)。

D-SACK 有这么几个好处:

  1. 可以让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了;
  2. 可以知道是不是「发送方」的数据包被网络延迟了;
  3. 可以知道网络中是不是把「发送方」的数据包给复制了;

在 Linux 下可以通过 net.ipv4.tcp_dsack 参数开启/关闭这个功能(Linux 2.4 后默认打开)。