飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • IP协议

    • 认识 IP 协议与网络层定位
    • IPv4 编址体系与分类地址
    • CIDR 与子网划分实战
    • IPv6 编址体系
    • ARP 协议详解
    • NDP 协议详解
    • IGMP 与 MLD 组播侦听发现
    • VRRP 与网关冗余
    • IPv4 数据报首部解析
    • IPv6 数据报与扩展首部
    • IPsec 安全扩展
    • 分片、MTU 与路径发现
    • ICMP 与 Traceroute 原理
    • 路由基础与转发流水线
    • 动态路由协议
    • NAT 网络地址转换
    • DHCP 与自动配置
    • Wireshark 与命令行工具
    • IPv6 过渡技术
    • IP 协议栈排障与攻击防御
  • TCP协议

    • 认识 TCP 协议与传输层定位
    • TCP 报文段首部解析
    • 三次握手与连接建立
    • 四次挥手与连接释放
    • TCP 有限状态机
    • 序列号与确认机制
    • 超时重传与 RTO 计算
    • 滑动窗口与流量控制
    • 拥塞控制基础
    • 现代拥塞控制算法
    • TCP 选项与扩展
    • TCP 性能调优与内核参数
    • Nagle 算法与糊涂窗口综合征
    • TCP 定时器与 Keep-Alive 机制
    • TCP 安全与攻击防御
    • TCP 与上层/下层交互
    • TCP 综合实践与排障

超时重传与 RTO 计算

为什么需要超时重传

TCP 承诺可靠传输,但 IP 网络可能丢包。发送方发出数据后,如果在合理时间内未收到 ACK,必须重传——这就是**超时重传(Retransmission Timeout, RTO)**机制。

RTO 的核心挑战:设太短,网络轻微延迟就触发不必要的重传(加剧拥塞);设太长,丢包后迟迟不恢复(降低吞吐)。RTO 必须动态自适应网络状况。

RTT 测量

RTT(Round-Trip Time,往返时间)= 报文发送时刻 → 收到对应 ACK 时刻的差值。

关键问题:如何确定 ACK 对应哪个报文?

Karn 算法:解决重传歧义

当定时器超时触发重传后,发送方无法区分收到的 ACK 是对原始报文还是重传报文的确认。Karn 算法规定:

重传后的 ACK 不用于更新 RTT 估计

指数退避(Exponential Backoff):每次重传后,RTO 加倍,直到上限(通常 64 秒)。

第 1 次重传:RTO = 2 × 当前 RTO
第 2 次重传:RTO = 4 × 原始 RTO
第 3 次重传:RTO = 8 × 原始 RTO
...
上限:RTO ≤ 64 秒

RTO 标准算法(RFC 6298)

RFC 6298(替代 RFC 793 的原始算法)定义了现代 TCP 的 RTO 计算:

初始化

SRTT = 首次测量的 RTT
RTTVAR = 首次测量的 RTT / 2
RTO = SRTT + 4 × RTTVAR

后续更新(收到新 RTT 样本时)

RTTVAR = (1 - β) × RTTVAR + β × |SRTT - RTT_sample|
SRTT = (1 - α) × SRTT + α × RTT_sample
RTO = SRTT + 4 × RTTVAR

传统取值:α = 1/8,β = 1/4

边界约束

  • RTO ≥ 1 秒(防止过短)
  • RTO ≤ 上限(通常 64 秒)
  • 重传后 RTO 加倍(指数退避)

计算示例

假设 α=1/8, β=1/4

第 1 次:RTT=100ms
  SRTT = 100ms
  RTTVAR = 50ms
  RTO = 100 + 4×50 = 300ms

第 2 次:RTT=120ms
  RTTVAR = 3/4×50 + 1/4×|100-120| = 37.5 + 5 = 42.5ms
  SRTT = 7/8×100 + 1/8×120 = 87.5 + 15 = 102.5ms
  RTO = 102.5 + 4×42.5 = 272.5ms

第 3 次:RTT=90ms
  RTTVAR = 3/4×42.5 + 1/4×|102.5-90| = 31.875 + 3.125 = 35ms
  SRTT = 7/8×102.5 + 1/8×90 = 89.6875 + 11.25 = 100.9375ms
  RTO = 100.9375 + 4×35 = 240.9375ms

观察:RTT 波动大时,RTTVAR 增大,RTO 保守;RTT 稳定时,RTTVAR 减小,RTO 激进。

时间戳选项与更精确的 RTT 测量

RFC 7323 引入时间戳选项后,RTT 测量更精确:

发送方在报文中放入 TSval(发送时刻)
接收方在 ACK 中回显 TSecr = 收到的 TSval
发送方收到 ACK 后:RTT = 当前时刻 - TSecr

优势:

  • 每个报文都有独立的时间戳,ACK 对应关系明确
  • 窗口大、ACK 稀少时仍能频繁采样 RTT
  • 支持 PAWS(防序列号回绕)

本篇小结

  • RTO 是 TCP 可靠性的最后防线,必须动态自适应
  • RTT 测量存在重传歧义:无法区分 ACK 对应原始报文还是重传报文
  • Karn 算法:重传后的 ACK 不用于更新 RTT,RTO 指数退避
  • RFC 6298 标准算法:SRTT + 4×RTTVAR,α=1/8, β=1/4
  • 边界:RTO ≥ 1 秒,重传后加倍,上限 64 秒
  • 时间戳选项:更精确的 RTT 测量 + PAWS

动手实践

  1. 查看 Linux RTO 相关参数:

    sysctl net.ipv4.tcp_rto_min
    sysctl net.ipv4.tcp_retries2
    
  2. Wireshark 抓包观察重传:

    • 过滤 tcp.analysis.retransmission
    • 观察原始报文与重传报文的时间差(即 RTO)
  3. 用 tc 模拟延迟,观察 RTO 自适应:

    sudo tc qdisc add dev eth0 root netem delay 100ms
    # 测试后删除
    sudo tc qdisc del dev eth0 root
    
  4. 手工计算:假设 SRTT=200ms, RTTVAR=50ms,新测得 RTT=300ms,更新后的 RTO 是多少?

上一页
序列号与确认机制
下一页
滑动窗口与流量控制