Skip to main content

3. Functional Specification - Part 1 (功能规范 - 第1部分)

本部分包含TCP的核心技术规范:头部格式、术语和序列号机制。


3.1. Header Format (头部格式)

TCP段 (TCP segments) 作为互联网数据报 (internet datagrams) 发送。互联网协议头部携带多个信息字段,包括源和目标主机地址 [2]。TCP头部跟随互联网头部,提供TCP协议特有的信息。这种划分允许存在除TCP之外的主机级协议。

TCP头部格式

    0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

TCP头部格式

注意: 一个刻度标记代表一个比特位置

字段详细说明

Source Port (源端口): 16位

源端口号。

用途: 标识发送方主机上的进程。

Destination Port (目标端口): 16位

目标端口号。

用途: 标识接收方主机上的进程。

Sequence Number (序列号): 32位

此段中第一个数据八位字节的序列号 (除非存在SYN)。如果存在SYN,则序列号是初始序列号 (Initial Sequence Number, ISN),第一个数据八位字节是ISN+1。

关键点:

  • 每个数据字节都有唯一的序列号
  • SYN段使用ISN,数据从ISN+1开始
  • 序列号空间: 0 到 2³² - 1

Acknowledgment Number (确认号): 32位

如果设置了ACK控制位,此字段包含段的发送者期望接收的下一个序列号的值。一旦建立连接,此字段始终发送。

累积确认机制:

  • 确认号为X表示所有小于X的字节已被接收
  • 不包括X本身

Data Offset (数据偏移): 4位

TCP头部中的32位字数。这指示数据从哪里开始。TCP头部 (即使包括选项) 是32位的整数倍长。

计算公式:

头部长度 (字节) = Data Offset × 4
最小值: 5 (20字节)
最大值: 15 (60字节)

Reserved (保留): 6位

保留供将来使用。必须 (MUST) 为零。

Control Bits (控制位): 6位 (从左到右)

标志全称含义
URGUrgent紧急指针字段有效
ACKAcknowledgment确认字段有效
PSHPushPush功能
RSTReset重置连接
SYNSynchronize同步序列号
FINFinish发送方没有更多数据

标志组合含义:

SYN = 1: 连接建立请求
SYN + ACK = 1: 连接建立响应
FIN = 1: 连接终止请求
RST = 1: 异常终止连接
PSH = 1: 立即推送数据到应用层
URG = 1: 存在紧急数据

Window (窗口): 16位

从确认字段中指示的八位字节开始,此段的发送者愿意接受的数据八位字节数。

流量控制:

  • 窗口大小 = 0: 停止发送数据
  • 窗口大小 > 0: 可发送窗口大小字节的数据
  • 最大窗口: 65,535字节 (可通过窗口缩放选项扩展)

示例:

ACK = 1000, Window = 5000
→ 可以接收序列号 1000-4999 的数据 (5000字节)

Checksum (校验和): 16位

校验和字段是头部和文本中所有16位字的补码和的16位补码。如果段包含奇数个要校验和的头部和文本八位字节,则最后一个八位字节在右侧填充零,以形成用于校验和目的的16位字。填充不作为段的一部分传输。在计算校验和时,校验和字段本身被替换为零。

伪头部 (Pseudo Header):

校验和还覆盖概念上前缀到TCP头部的96位伪头部。此伪头部包含源地址、目标地址、协议和TCP长度。这为TCP提供了对错误路由段的保护。

+--------+--------+--------+--------+
| Source Address |
+--------+--------+--------+--------+
| Destination Address |
+--------+--------+--------+--------+
| zero | PTCL | TCP Length |
+--------+--------+--------+--------+

PTCL = 6 (TCP协议号)
TCP Length = TCP头部长度 + 数据长度 (以八位字节为单位)

校验和计算步骤:

def calculate_tcp_checksum(pseudo_header, tcp_header, data):
# 1. 将校验和字段设为0
# 2. 组合伪头部、TCP头部和数据
# 3. 按16位字累加
# 4. 将进位加到低16位
# 5. 取补码
pass

Urgent Pointer (紧急指针): 16位

此字段传达紧急指针的当前值,作为此段中序列号的正偏移量。紧急指针指向紧急数据后面的八位字节的序列号。此字段仅在设置了URG控制位的段中解释。

使用场景:

  • Ctrl+C 中断信号
  • Telnet中断命令
  • 需要优先处理的控制信息

示例:

SEG.SEQ = 1000
URG Pointer = 10
→ 紧急数据结束于序列号 1010
→ 序列号 1000-1009 是紧急数据

Options (选项): 可变

选项可以占用TCP头部末尾的空间,长度为8位的倍数。所有选项都包含在校验和中。选项可以从任何八位字节边界开始。选项格式有两种情况:

情况1: 单个八位字节的option-kind 情况2: 一个八位字节的option-kind,一个八位字节的option-length,以及实际的option-data八位字节

option-length计算option-kind和option-length两个八位字节以及option-data八位字节。

重要: TCP必须 (MUST) 实现所有选项。

当前定义的选项

Kind (八进制)Length含义
0-选项列表结束 (End of Option List)
1-无操作 (No-Operation)
24最大段大小 (Maximum Segment Size)

选项详细说明

1. End of Option List (选项列表结束)

+--------+
|00000000|
+--------+
Kind=0
  • 此选项代码指示选项列表的结束
  • 这可能不与根据Data Offset字段的TCP头部的结束重合
  • 用于所有选项的结束,而不是每个选项的结束
  • 仅在选项的结束不会与TCP头部的结束重合时需要使用

2. No-Operation (无操作)

+--------+
|00000001|
+--------+
Kind=1
  • 此选项代码可以在选项之间使用
  • 例如,将后续选项的开头对齐到字边界
  • 不保证发送方将使用此选项
  • 接收方必须准备好处理不从字边界开始的选项

3. Maximum Segment Size (最大段大小)

+--------+--------+---------+--------+
|00000010|00000100| max seg size |
+--------+--------+---------+--------+
Kind=2 Length=4

Maximum Segment Size Option Data: 16位

  • 如果存在此选项,则它传达发送此段的TCP的最大接收段大小
  • 此字段必须仅在初始连接请求中发送 (即,在设置了SYN控制位的段中)
  • 如果不使用此选项,则允许任何段大小

MSS说明:

  • 默认MSS = 536字节 (互联网默认)
  • 以太网常用MSS = 1460字节 (1500 - 20 IP头 - 20 TCP头)
  • MSS仅指数据部分,不包括TCP/IP头部

Padding (填充): 可变

TCP头部填充用于确保TCP头部在32位边界上结束,数据在32位边界上开始。填充由零组成。


3.2. Terminology (术语)

在我们讨论TCP操作之前,需要引入一些详细的术语。TCP连接的维护需要记住几个变量。我们设想这些变量存储在称为传输控制块 (Transmission Control Block, TCB) 的连接记录中。

TCB中存储的变量

TCB中存储的变量包括:

  • 本地和远程套接字号
  • 连接的安全性和优先级
  • 指向用户发送和接收缓冲区的指针
  • 指向重传队列和当前段的指针
  • 与发送和接收序列号相关的几个变量

发送序列变量 (Send Sequence Variables)

变量全称说明
SND.UNASend Unacknowledged发送未确认 (最老的未确认序列号)
SND.NXTSend Next发送下一个 (下一个要发送的序列号)
SND.WNDSend Window发送窗口
SND.UPSend Urgent Pointer发送紧急指针
SND.WL1Segment Sequence Number用于上次窗口更新的段序列号
SND.WL2Segment Acknowledgment Number用于上次窗口更新的段确认号
ISSInitial Send Sequence Number初始发送序列号

接收序列变量 (Receive Sequence Variables)

变量全称说明
RCV.NXTReceive Next接收下一个 (下一个期望的序列号)
RCV.WNDReceive Window接收窗口
RCV.UPReceive Urgent Pointer接收紧急指针
IRSInitial Receive Sequence Number初始接收序列号

序列空间图示

发送序列空间 (Send Sequence Space)

                 1         2          3          4
----------|----------|----------|----------
SND.UNA SND.NXT SND.UNA
+SND.WND

1 - 已确认的旧序列号
2 - 未确认数据的序列号
3 - 允许新数据传输的序列号
4 - 尚不允许的未来序列号

发送窗口: 图中标记为3的序列空间部分

接收序列空间 (Receive Sequence Space)

                     1          2          3
----------|----------|----------
RCV.NXT RCV.NXT
+RCV.WND

1 - 已确认的旧序列号
2 - 允许新接收的序列号
3 - 尚不允许的未来序列号

接收窗口: 图中标记为2的序列空间部分

当前段变量 (Current Segment Variables)

这些变量从当前段的字段中获取值:

变量说明
SEG.SEQ段序列号
SEG.ACK段确认号
SEG.LEN段长度
SEG.WND段窗口
SEG.UP段紧急指针
SEG.PRC段优先级值

连接状态 (Connection States)

连接在其生命周期中经历一系列状态。状态包括: LISTEN, SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT 和虚构状态 CLOSED

状态详细说明

状态说明
LISTEN表示等待来自任何远程TCP和端口的连接请求
SYN-SENT表示在发送连接请求后等待匹配的连接请求
SYN-RECEIVED表示在接收和发送连接请求后等待确认连接请求确认
ESTABLISHED表示打开的连接,可以将接收的数据交付给用户。连接的数据传输阶段的正常状态
FIN-WAIT-1表示等待来自远程TCP的连接终止请求,或先前发送的连接终止请求的确认
FIN-WAIT-2表示等待来自远程TCP的连接终止请求
CLOSE-WAIT表示等待来自本地用户的连接终止请求
CLOSING表示等待来自远程TCP的连接终止请求确认
LAST-ACK表示等待先前发送到远程TCP的连接终止请求的确认 (其中包括其连接终止请求的确认)
TIME-WAIT表示等待足够的时间以确保远程TCP收到其连接终止请求的确认
CLOSED表示根本没有连接状态 (虚构状态,因为它表示没有TCB时的状态)

TCP连接状态图

                            +---------+ ---------\      active OPEN
| CLOSED | \ -----------
+---------+<---------\ \ create TCB
| ^ \ \ snd SYN
passive OPEN | | CLOSE \ \
------------ | | ---------- \ \
create TCB | | delete TCB \ \
V | \ \
+---------+ CLOSE | \
| LISTEN | ---------- | |
+---------+ delete TCB | |
rcv SYN | | SEND | |
----------- | | ------- | V
+---------+ snd SYN,ACK / \ snd SYN +---------+
| |<----------------- ------------------>| |
| SYN | rcv SYN | SYN |
| RCVD |<-----------------------------------------------| SENT |
| | snd ACK | |
| |------------------ -------------------| |
+---------+ rcv ACK of SYN \ / rcv SYN,ACK +---------+
| -------------- | | -----------
| x | | snd ACK
| V V
| CLOSE +---------+
| ------- | ESTAB |
| snd FIN +---------+
| CLOSE | | rcv FIN
V ------- | | -------
+---------+ snd FIN / \ snd ACK +---------+
| FIN |<----------------- ------------------>| CLOSE |
| WAIT-1 |------------------ | WAIT |
+---------+ rcv FIN \ +---------+
| rcv ACK of FIN ------- | CLOSE |
| -------------- snd ACK | ------- |
V x V snd FIN V
+---------+ +---------+ +---------+
|FINWAIT-2| | CLOSING | | LAST-ACK|
+---------+ +---------+ +---------+
| rcv ACK of FIN | rcv ACK of FIN |
| rcv FIN -------------- | Timeout=2MSL -------------- |
| ------- x V ------------ x V
\ snd ACK +---------+delete TCB +---------+
------------------------>|TIME WAIT|------------------>| CLOSED |
+---------+ +---------+

TCP连接状态图

事件和状态转换

TCP连接响应事件从一个状态进展到另一个状态。事件包括:

  • 用户调用: OPEN, SEND, RECEIVE, CLOSE, ABORT, STATUS
  • 传入段: 特别是包含SYN, ACK, RST和FIN标志的段
  • 超时: 重传超时、TIME-WAIT超时等

注意: 状态图仅是摘要,不能作为完整规范。它只说明状态变化,以及导致事件和结果操作,但既不处理错误条件,也不处理与状态变化无关的操作。


3.3. Sequence Numbers (序列号)

基本概念

TCP设计中的一个基本概念是通过TCP连接发送的每个数据八位字节都有一个序列号。由于每个八位字节都被排序,因此可以确认它们中的每一个。采用的确认机制是累积的 (cumulative),因此序列号X的确认表示所有八位字节直到但不包括X都已被接收

这种机制允许在重传存在的情况下进行直接的重复检测。段内八位字节的编号是头部后面的第一个数据八位字节编号最低,后续八位字节连续编号。

序列号空间

关键事实: 实际序列号空间是有限的,尽管非常大。此空间范围从0到2³² - 1。

模运算 (Modulo Arithmetic): 由于空间是有限的,所有处理序列号的算术必须以模2³²执行。这种无符号算术保持序列号从2³² - 1循环到0时的关系。计算机模运算有一些微妙之处,因此在编程此类值的比较时应格外小心。

符号约定:

  • 符号=<表示"小于或等于" (模2³²)

序列号比较

TCP必须执行的典型序列号比较包括:

  1. 确定确认引用某个已发送但尚未确认的序列号
  2. 确定段占用的所有序列号都已被确认 (例如,从重传队列中删除段)
  3. 确定传入段包含预期的序列号 (即,段"重叠"接收窗口)

发送端序列号处理

响应发送数据,TCP将接收确认。需要以下比较来处理确认:

SND.UNA = 最老的未确认序列号
SND.NXT = 下一个要发送的序列号
SEG.ACK = 接收TCP的确认 (接收TCP期望的下一个序列号)
SEG.SEQ = 段的第一个序列号
SEG.LEN = 段中数据占用的八位字节数 (计入SYN和FIN)
SEG.SEQ+SEG.LEN-1 = 段的最后一个序列号

可接受的确认 (Acceptable ACK):

新确认 (称为"可接受的确认") 是满足以下不等式的确认:

SND.UNA < SEG.ACK ≤ SND.NXT

如果段的序列号和长度之和小于或等于传入段中的确认值,则重传队列上的段被完全确认。

示例:

SND.UNA = 1000 (最老未确认)
SND.NXT = 2000 (下一个发送)

收到 SEG.ACK = 1500
检查: 1000 < 1500 ≤ 2000 ✓ (可接受)

收到 SEG.ACK = 2500
检查: 1000 < 2500 ≤ 2000 ✗ (不可接受,确认了未发送的数据)

接收端序列号处理

当接收数据时,需要以下比较:

RCV.NXT = 传入段上期望的下一个序列号,
是接收窗口的左边或下边缘

RCV.NXT+RCV.WND-1 = 传入段上期望的最后一个序列号,
是接收窗口的右边或上边缘

SEG.SEQ = 传入段占用的第一个序列号
SEG.SEQ+SEG.LEN-1 = 传入段占用的最后一个序列号

段的可接受性测试

段如果其序列号在窗口内,则被认为是可接受的。测试取决于段长度和窗口大小:

段长度窗口大小可接受性测试
00SEG.SEQ = RCV.NXT
0>0RCV.NXT ≤ SEG.SEQ < RCV.NXT+RCV.WND
>00不可接受
>0>0RCV.NXT ≤ SEG.SEQ < RCV.NXT+RCV.WND

RCV.NXT ≤ SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND

说明:

  • 零长度段的第一个测试可以看作是对伪段的测试,该伪段从SEG.SEQ开始,并且不占用序列空间
  • 如果RCV.WND为零,则不接受数据,但接受不占用空间的段

实际代码示例:

def is_segment_acceptable(seg_seq, seg_len, rcv_nxt, rcv_wnd):
"""检查段是否可接受"""
if seg_len == 0:
if rcv_wnd == 0:
return seg_seq == rcv_nxt
else:
return rcv_nxt <= seg_seq < rcv_nxt + rcv_wnd
else: # seg_len > 0
if rcv_wnd == 0:
return False
else:
# 段的开始或结束在窗口内
start_in_window = rcv_nxt <= seg_seq < rcv_nxt + rcv_wnd
end_in_window = rcv_nxt <= seg_seq + seg_len - 1 < rcv_nxt + rcv_wnd
return start_in_window or end_in_window

初始序列号选择 (ISN)

初始序列号 (ISN) 的选择非常重要。TCP必须使用基于时钟的ISN生成器,以避免旧连接段被误认为是新连接的一部分。

ISN生成建议:

  • ISN应该每4微秒增加1
  • ISN有大约4.55小时的周期
  • 新连接的ISN应该不同于旧连接的ISN

安全考虑:

  • 现代实现应使用更安全的ISN生成算法 (RFC 6528)
  • 防止序列号预测攻击

关键概念总结

TCP头部结构

  • 固定20字节头部: 包含所有核心字段
  • 可变长度选项: 最多40字节
  • 校验和覆盖伪头部: 提供额外的错误检测

序列号机制

  • 每字节编号: 每个数据字节都有唯一的序列号
  • 累积确认: 确认号表示所有小于该号的字节已收到
  • 模2³²运算: 序列号空间是循环的

连接状态

  • 11个状态: 从CLOSED到ESTABLISHED再到CLOSED
  • 事件驱动: 用户调用、段到达、超时触发状态转换
  • 三次握手: SYN → SYN-ACK → ACK
  • 四次挥手: FIN → ACK → FIN → ACK

TCB变量

  • 发送变量: SND.UNA, SND.NXT, SND.WND等
  • 接收变量: RCV.NXT, RCV.WND等
  • 窗口管理: 流量控制的核心

下一部分: 3.4-3.9 Connection Management & Event Processing - 连接建立、关闭、数据通信和事件处理的详细规范