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

    • TCP协议
  • 数据库

    • SQL教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

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

    • TCP协议
  • 数据库

    • SQL教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • TCP协议

    • TCP 简介与分层模型
    • TCP 连接管理
    • TCP 可靠传输机制
    • TCP 粘包与拆包
    • TCP 拥塞控制
    • TCP 头部字段详解
    • TCP 与 UDP 对比
    • TCP Socket 编程实践
    • TCP 抓包实战
    • TCP 安全与面试综合题

TCP 可靠传输机制

序列号、确认应答、超时重传、滑动窗口 — TCP 如何在不可靠的网络上保证可靠传输?


1. 可靠的基石:序列号与确认

RFC 9293 明确指出:TCP 连接上发送的每个字节都有一个序列号。32 位序列号空间从 0 到 2^32-1(约 4.3 GB),循环使用。

1.1 序列号(Sequence Number)

TCP 为每个发送的字节编号。段头部的序列号字段是该段中第一个数据字节的序列号。

段中数据:[ 字节A | 字节B | 字节C | 字节D ]
             ↑
        SEQ = 序列号(A)

注意:SYN 和 FIN 标志也消耗一个序列号。携带 SYN 的段,SEQ 就是 ISN,第一个数据字节的序列号为 ISN+1。

1.2 确认号(Acknowledgment Number)

确认号表示"我期望收到的下一个字节的序列号"。TCP 使用累积确认——ACK=X 意味着 X-1 及之前的所有字节都已收到。

发送方                              接收方
  |── seq=100, data(200字节) ──→|   收到 100~299
  |                           |
  |←── ack=300 ────────────────|   "我要第 300 号"

2. 超时重传(RTO)

2.1 RTO 的计算

TCP 根据测量的往返时间(RTT)动态计算重传超时(RTO)。RFC 6298 规定的经典算法:

SRTT = (1-α) × SRTT + α × RTT_measured      (α = 1/8)
RTTVAR = (1-β) × RTTVAR + β × |SRTT - RTT_measured|  (β = 1/4)
RTO = SRTT + max(G, 4 × RTTVAR)              (G = 时钟粒度)

2.2 Karn 算法

问题:重传后收到的 ACK,无法区分是对原始段还是重传段的确认。如果误用会导致 RTT 估算严重失真。

Karn 算法:重传的段不用于更新 RTT 估计。当收到重传段的 ACK 时,RTO 翻倍(指数退避),直到收到非重传段的 ACK。

2.3 重传策略

  • 超时未收到 ACK → 重传最早的未确认段 → RTO 翻倍
  • 连续重传多次(通常 5-15 次)仍未成功 → 认为连接失效,发送 RST 关闭

3. 滑动窗口(Sliding Window)

滑动窗口是 TCP 实现流量控制的核心机制。

3.1 窗口的概念

接收方通过 TCP 头部的窗口大小字段(16 位,最大 65535 字节,可用窗口缩放选项扩展)告知发送方:

"我还能收多少字节,请别发超了"

发送方窗口:
├──── 已发送已确认 ────┼── 已发送未确认 ──┼── 可发送未发送 ──┼── 不可发送 ────┤
                      ↑ SND.UNA           ↑ SND.NXT         ↑ SND.UNA+SND.WND
                      ←─── SND.WND ──────→

3.2 窗口滑动

随着 ACK 到达,窗口向右滑动:

ACK 前: [已确认...|未确认...|可发送...|不可发送...]
ACK 后: [........已确认........|未确认...|可发送...|不可发送...]
                               ← 窗口右移 →

3.3 零窗口处理

当接收方窗口为 0 时,发送方停止发送并启动持续定时器(Persist Timer),周期性发送窗口探测段(1 字节数据),检查窗口是否恢复。

窗口综合症(Silly Window Syndrome):接收方每次只释放很小窗口(如 1 字节),发送方每次只发很少数据。双方均使用 Clark 算法避免:

  • 接收方:窗口足够大(至少 1 MSS 或缓冲区的一半)才通告
  • 发送方:积累足够数据(至少 1 MSS 或窗口的一半)才发送

4. 流量控制 vs 拥塞控制

维度流量控制拥塞控制
目的防止发送方淹没接收方防止发送方淹没网络
关注对象接收方的处理能力网络的承载能力
核心机制滑动窗口(rwnd)拥塞窗口(cwnd)
信息来源接收方通告窗口大小丢包/延迟等网络信号
发送上限min(cwnd, rwnd)—

发送方实际可发送量 = min(拥塞窗口 cwnd, 接收方通告窗口 rwnd)


5. 选择性确认(SACK)

传统 TCP 只支持累积确认——ACK=X 表示 X 之前的所有字节都收到了。如果一个段丢失,即使后面的段都收到了,ACK 还是指向丢失处,发送方需要重传丢失段及之后所有段。

SACK(Selective Acknowledgment)[RFC 2018] 允许接收方通过 TCP 选项告知发送方:

"我收到了字节 1000-1999 和 3000-3999,但 2000-2999 丢了"

发送方可以只重传丢失的 2000-2999,不需要重传 3000-3999。这在长肥管道(LFN)上显著提升性能。


6. 小结

TCP 的可靠传输由多个机制协同实现:

  1. 序列号:每个字节有编号,保证有序
  2. 确认应答:累积确认,知道哪些数据已到达
  3. 超时重传:未确认的数据有人兜底重发
  4. 滑动窗口:接收方说"只能收这么多",发送方不超发
  5. SACK:精准定位丢失段,避免不必要的重传

这些机制让 TCP 在不可靠的 IP 网络上实现了"万无一失"。


本篇要点

  • TCP 可靠传输的六大机制:序列号、确认应答(累积确认)、超时重传、校验和、滑动窗口(流量控制)、拥塞控制
  • 累积确认:ACK=N 表示 N-1 及之前的所有字节都已收到;优点是实现简单,缺点是一个段丢失会阻塞后续确认
  • RTO 动态计算:RTO = SRTT + 4×RTTVAR,Karn 算法规定重传段不用于 RTT 估算(避免二义性)
  • 滑动窗口实现流量控制:接收方通过窗口大小告知发送方能收多少,窗口为 0 时发送方启动持续定时器探测
  • SACK(选择性确认)让发送方只重传真正丢失的段,避免累积确认导致的不必要重传
  • 发送方实际可发送量 = min(拥塞窗口 cwnd, 接收方通告窗口 rwnd)
  • 判断重传的两种方式:超时重传(RTO 到期)和快速重传(连续 3 个重复 ACK)
上一页
TCP 连接管理
下一页
TCP 粘包与拆包