概述

  • 为了使 TCP 能够提供应用程序所需的数据传输功能和质量,必须对协议进行增强。不仅管理基本的数据传输过程,还用于确保数据的可靠发送,并管理设备之间的数据流,以确保数据的有效传输。而不是使设备发送速度快于另一设备的接收数据的速度。
  • TCP 要保证所有的数据包都能正解到达接收端,必须提供可靠传输。而 超时重传机制 则是可靠传输中的一环。
  • TCP 对于完成重传有两个单独的机制:

    • 基于时间。
    • 基于 ACK。

      超时重传机制(基于时间)

  • 检测丢失报文并重新传输它们的操作是简单的。每次发送一个报文,我们就启动一个 重传计时器。这个重传计时器以一个预先设定的值开始计算,如果在收到该报文的确认(即 ACK)之前 重传计时器 到期,TCP 将重传该报文段。

  • TCP 系统按以下特定顺序工作:
    • 副本写入 重传队列,启动重传计时器。
      • TCP 在实现上使用 重传队列(Retransmission Queue) 保存正在发送的数据的副本。当副本放置重传队列时就会对该副本启动一个 重传计时器。在重传队列中会按照重传计时器剩余的时间进行排序。因此,TCP 可以哪个计时器在过期前剩余的时间最小。
    • 处理 ACK。
      • 在某个报文段的重传计时器到期之前收到该报文段的确认,则将该报文段从队列中队列。
    • 超时重传(Retransmission Timeout)。
      • TCP 自动对重传计时器过期的报文段进行重传操作。
  • TCP 并非无限制重传,当达到一定次数,就断定当前连接存在问题并终止连接。
  • 影响 超时重传机制 协议效率的一个关键参数是重传超时时间(Retransmission TimeOut, RTO)。需要根据网络情况动态变化。
  • 缺陷
    • 如果只依赖重传计时器对丢包数据进行重传会导致网络效率非常低下,网络带宽使用率不高。因为,发送端需要等待至少 RTO 时长才能重传报文,而且在没有 SACK 机制情况下,会重传丢包序列号后面的所有数据。
    • 因此,超时重传机制应当作为兜底的解决方案,不能用作一般方案。
  • 简单的带有TCP事务的重传示例

带有重传的TCP事务示例.png
步骤8重传计时器过期,于是服务端发送丢失报文段(起始序列号为201)。由于使用 SACK 选项机制,因此,服务器知道接收端已收到的报文和丢失报文,所以能做到精确重传。

快速重传机制(基于 ACK)

超时重传机制是 TCP 可靠性的重要的保障功能,但是假设网络上的拥塞急剧拉回,并且没有适当的机制来处理拥塞,报文段被延迟或丢弃,这将导致发送端超时重传,如此一来,这将增加客户端和服务端之间的网络拥塞,导致恶性循环。因此,基于 ACK 的快速重传机制能有效解决这一问题。

  • 不以时间驱动数据传送,而是以 数据驱动重传。
  • 如果发送方连接收到 3次dupthresh) 相同的 ACK,表示大概率丢了包,于是进行重传。_Fast Retransmit_ 的好处是不用等超时了再进行重传动作。
  • _Fast Retransmit_ 只解决 超时 问题,但还是没有解决重传后续所有已发送的分组还是只重传收到 3个 ACK 的分组呢? 可见,并不能靠 _Fast Retransmit_ 完美解决所有问题。

    为什么只能收到3次重复ACK才进行快速重传

  • 两次重复的 ACK 很可能是乱序造成的。

  • 三次重复的 ACK 很大概率是丢包造成的。
  • 四次重复的 ACK 极大概率是丢包造成的。
  • 导致丢包的大致原因可以归纳如下:

    • 检验和出错。
    • 网络拥塞。
    • 网络断开连接,包括路由重收敛。

      SACK

  • _**Selective Acknowledgment, SACK**_。选择性确认。属于 TCP 扩展选项之一。此功能在 RFC1072 引入,并在 RFC2018 中进行改进。

  • 要使用 SACK 功能必须两端都支持,且在三次握手时两端进行协商,在扩展字段中添加是否本机支持 SACK 功能。
  • SACK 是用来解决非连续确认报文。如果两端允许 SACK,则在 TCP 首部扩展字段中包含接收端已接收但未确认的报文段的序列号范围列表。它们是不连续的。
  • 和重传计时器相比,可选的 TCP 选择性重传 提供了一种更优雅的方式处理非连接报文段。即便这些报文段没被确认,但可以让发送端避免重复发送。
  • Linux 2.4 默认提供支持。

SACK_TCP 重传.png
带有选择性确认(SACK) 的TCP 重传

Duplicate SACK

  • 又称 D-SACK,RFC2883 对 D-SACK 有更详细的描述。
  • 主要使用了 SACK 来告诉发送方有哪些数据被重复接收了。
  • 引入 D-SACK 有以下好处:
    • 可以让发送方知道,是发出的包丢了,还是回来的 ACK 包丢了。
    • 是不是自己的 timeout 太小了,导致重传。
    • 网络上出现了先发的包后到的情况。
    • 网络上是不是把我的数据包给复制了。
  • 知道这些东西可以更好帮助 TCP 了解网络情况,从而更好的做网络上的流量控制。