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

    • 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 综合实践与排障

TCP 选项与扩展

TCP 选项机制

TCP 首部固定 20 字节,但通过**选项(Options)**机制可扩展至 60 字节。选项采用 TLV(Type-Length-Value) 编码:

+--------+--------+--------+--------+...
|  Type  | Length |        Value        |
| 1 byte | 1 byte |  (Length-2) bytes   |
+--------+--------+--------+--------+...
  • Type:选项类型(如 2=MSS, 3=Window Scale)
  • Length:整个选项的字节数(包括 Type 和 Length 字段)
  • Value:选项数据

关键限制:选项空间仅 40 字节(60-20),迫使扩展必须紧凑编码。

选项仅在三次握手时通过 SYN 报文协商,连接建立后不可动态变更。

MSS(Maximum Segment Size,选项类型 2)

MSS 是 TCP 报文段中数据部分的最大长度,不包括 TCP 首部。

MSS = MTU - IP 首部(20) - TCP 首部(20) = 1500 - 40 = 1460 字节

协商过程:

  • 客户端 SYN:"我的 MSS 是 1460"
  • 服务端 SYN-ACK:"我的 MSS 是 1460"
  • 双方取较小值作为实际 MSS

如果路径 MTU 更小(如 PPPoE MTU=1492、VPN 隧道):

  • 理想情况:PMTUD 探测路径 MTU,自动调整
  • fallback:TCP 发现 IP 层分片或收到 ICMP "需要分片",降低 MSS

窗口缩放(Window Scale,选项类型 3,RFC 7323)

原始 Window 字段 16 位,最大 65535 字节。窗口缩放通过 Shift Count(0~14) 突破限制:

实际窗口 = Window 字段值 × 2^ShiftCount

协商过程:

  • 客户端 SYN:"我支持窗口缩放,Shift Count = 8"
  • 服务端 SYN-ACK:"我也支持,Shift Count = 8"
  • 后续报文中 Window 字段需左移 8 位

最大实际窗口:65535 × 2^14 ≈ 1GB

现代操作系统默认启用(Linux net.ipv4.tcp_window_scaling=1)。

SACK(Selective ACK,选项类型 5,RFC 2018)

SACK 允许接收方精确通告已收到的乱序段边界,发送方仅重传真正丢失的段。

SACK 选项格式(最多 3~4 个块,受 40 字节限制):

+--------+--------+--------+--------+--------+--------+...
|  Type  | Length |  Left Edge 1 | Right Edge 1 | ... |
|   5    |  N     |   4 bytes   |   4 bytes    | ... |
+--------+--------+--------+--------+--------+--------+...

示例:段 1(1000~1099)和段 3(1200~1299)收到,段 2(1100~1199)丢失:

ACK=1100(累积确认,期望段 2)
SACK: 1200~1299(段 3 已收到)

发送方知道只需重传段 2,避免重传段 3。

现代操作系统默认启用 SACK(Linux net.ipv4.tcp_sack=1)。

时间戳(Timestamp,选项类型 8,RFC 7323)

10 字节选项,包含两个 4 字节字段:

  • TSval(Timestamp Value):发送方当前时间戳
  • TSecr(Timestamp Echo Reply):回显对方上次发送的 TSval

两大用途:

1. 更精确的 RTT 测量

发送方发送: TSval = T1
接收方回复: TSecr = T1
发送方收到 ACK: RTT = 当前时间 - T1

每个报文有独立时间戳,ACK 对应关系明确,窗口大、ACK 稀少时仍能频繁采样。

2. PAWS(Protection Against Wrapped Sequence numbers)

高速网络中序列号可能 3 秒回绕。PAWS 利用时间戳区分新旧报文:

  • 接收方记录最近收到的时间戳
  • 新报文的时间戳必须 ≥ 记录值
  • 时间戳过旧的报文丢弃

TCP Fast Open(TFO,选项类型 34,RFC 7413)

正常三次握手需要 1 个 RTT 才能发送数据。TFO 允许在首次 SYN 中携带数据,减少 1 个 RTT:

TFO Cookie:

  • 服务端生成(基于客户端 IP、密钥等)
  • 客户端缓存(通常几分钟)
  • 服务端验证 Cookie 有效后才接受 SYN 中的数据

适用场景:Web 短连接(REST API)、频繁重连的应用。

其他重要选项

选项类型作用
NOP1填充对齐(无操作)
EOL0选项列表结束
SACK-Permitted4握手时声明支持 SACK
TCP-AO29认证选项(替代 MD5)

本篇小结

  • TCP 选项 TLV 编码,最大 40 字节,握手时协商
  • MSS(2):协商最大段大小,典型 1460
  • Window Scale(3):Shift Count 0~14,突破 64KB 窗口限制
  • SACK(5):精确通告乱序段,仅重传丢失段
  • Timestamp(8):精确测 RTT + PAWS 防序列号回绕
  • TFO(34):SYN 带数据,减少 1 RTT
  • 现代系统默认启用 Window Scale + SACK + Timestamp

动手实践

  1. Wireshark 抓包观察 SYN 选项:

    • 右键 SYN 报文 → "TCP Stream" → 查看选项详情
    • 记录 MSS、Window Scale、SACK、Timestamp、TFO
  2. 查看 Linux 选项开关:

    sysctl net.ipv4.tcp_window_scaling
    sysctl net.ipv4.tcp_sack
    sysctl net.ipv4.tcp_timestamps
    
  3. 查看 TFO 设置:

    sysctl net.ipv4.tcp_fastopen
    
  4. 思考:为什么选项只能在握手时协商,而不能在连接中动态变更?如果窗口缩放可以在中途调整,会有什么技术难题?

上一页
现代拥塞控制算法
下一页
TCP 性能调优与内核参数