3. 功能规范 - 第一部分 (Functional Specification - Part 1)
本节包含 TCP 的核心技术规范: 头部格式 (header format), 术语 (terminology), 以及序列号机制 (sequence number mechanisms).
3.1. 头部格式 (Header Format)
TCP segments 作为 internet datagrams 发送. Internet Protocol header 携带多个信息字段, 包括源主机地址和目标主机地址 [2]. TCP header 跟在 internet header 之后, 提供 TCP protocol 专用的信息. 这种划分允许存在 TCP 之外的其他主机级协议.
TCP Header Format
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 Header Format
Note: One tick mark represents one bit position
字段说明 (Field Descriptions)
Source Port: 16 bits
源端口号.
用途 (Purpose): 标识发送主机上的发送进程.
Destination Port: 16 bits
目标端口号.
用途 (Purpose): 标识接收主机上的接收进程.
Sequence Number: 32 bits
本 segment 中第一个数据 octet 的序列号 (存在 SYN 时除外). 如果存在 SYN, sequence number 是初始序列号 (Initial Sequence Number, ISN), 第一个数据 octet 为 ISN+1.
要点 (Key Points):
- 每个数据 byte 都有唯一的 sequence number
- SYN segments 使用 ISN, 数据从 ISN+1 开始
- Sequence number space: 0 到 2³² - 1
Acknowledgment Number: 32 bits
如果 ACK control bit 已设置, 此字段包含 segment 发送方期望接收的下一个 sequence number. 一旦连接建立, 该字段始终会被发送.
累计确认机制 (Cumulative Acknowledgment Mechanism):
- Acknowledgment number 为 X 表示已经收到直到但不包括 X 的所有 bytes
- X 本身不包含在确认范围内
Data Offset: 4 bits
TCP Header 中 32-bit words 的数量. 它指示数据从哪里开始. TCP header (即使包含 options) 的长度也是 32 bits 的整数倍.
计算公式 (Calculation Formula):
Header Length (bytes) = Data Offset × 4
Minimum value: 5 (20 bytes)
Maximum value: 15 (60 bytes)
Reserved: 6 bits
保留供未来使用. Must be zero.
Control Bits: 6 bits (from left to right)
| Flag | Full Name | 含义 (Meaning) |
|---|---|---|
| URG | Urgent | Urgent Pointer field valid |
| ACK | Acknowledgment | Acknowledgment field valid |
| PSH | Push | Push function |
| RST | Reset | Reset the connection |
| SYN | Synchronize | Synchronize sequence numbers |
| FIN | Finish | No more data from sender |
Flag 组合 (Flag Combinations):
SYN = 1: Connection establishment request
SYN + ACK = 1: Connection establishment response
FIN = 1: Connection termination request
RST = 1: Abnormal connection termination
PSH = 1: Push data immediately to application layer
URG = 1: Urgent data present
Window: 16 bits
从 acknowledgment field 所指示的 octet 开始, 此 segment 发送方愿意接受的数据 octets 数量.
流量控制 (Flow Control):
- Window size = 0: 停止发送数据
- Window size > 0: 最多可发送 window size bytes
- Maximum window: 65,535 bytes (可通过 window scaling option 扩展)
示例 (Example):
ACK = 1000, Window = 5000
→ Can receive data with sequence numbers 1000-4999 (5000 bytes)
Checksum: 16 bits
Checksum field 是 header 和 text 中所有 16-bit words 的 one's complement sum 再取 one's complement 后得到的 16-bit 值. 如果某个 segment 中需要计算 checksum 的 header 和 text octets 数量为奇数, 最后一个 octet 会在右侧填充 zeros 以形成用于 checksum 的 16-bit word. 该填充不会作为 segment 的一部分传输. 计算 checksum 时, checksum field 自身替换为 zeros.
伪头部 (Pseudo Header):
Checksum 还覆盖一个概念上位于 TCP header 前面的 96-bit pseudo header. 该 pseudo header 包含 source address, destination address, protocol 和 TCP length. 这为 TCP 提供了防止 segment 被错误路由的保护.
+--------+--------+--------+--------+
| Source Address |
+--------+--------+--------+--------+
| Destination Address |
+--------+--------+--------+--------+
| zero | PTCL | TCP Length |
+--------+--------+--------+--------+
PTCL = 6 (TCP protocol number)
TCP Length = TCP header length + data length (in octets)
Checksum 计算步骤 (Checksum Calculation Steps):
def calculate_tcp_checksum(pseudo_header, tcp_header, data):
# 1. Set checksum field to 0
# 2. Combine pseudo header, TCP header, and data
# 3. Sum as 16-bit words
# 4. Add carry to low 16 bits
# 5. Take one's complement
pass
Urgent Pointer: 16 bits
此字段把 urgent pointer 的当前值表示为相对于本 segment 中 sequence number 的正偏移量. Urgent pointer 指向 urgent data 之后那个 octet 的 sequence number. 只有在设置 URG control bit 的 segments 中才解释此字段.
使用场景 (Use Cases):
- Ctrl+C interrupt signals
- Telnet interrupt commands
- 需要优先处理的控制信息
示例 (Example):
SEG.SEQ = 1000
URG Pointer = 10
→ Urgent data ends at sequence number 1010
→ Sequence numbers 1000-1009 are urgent data
Options: variable
Options 可以占用 TCP header 末尾的空间, 其长度为 8 bits 的倍数. 所有 options 都包含在 checksum 中. 一个 option 可以从任意 octet boundary 开始. Options 有两种格式:
Case 1: 单个 option-kind octet Case 2: 一个 option-kind octet, 一个 option-length octet, 以及实际的 option-data octets
option-length 计入 option-kind 和 option-length 这两个 octets, 也计入 option-data octets.
重要 (Important): TCP must implement all options.
当前定义的选项 (Currently Defined Options)
| Kind (octal) | Length | 含义 (Meaning) |
|---|---|---|
| 0 | - | End of Option List |
| 1 | - | No-Operation |
| 2 | 4 | Maximum Segment Size |
选项细节 (Option Details)
1. End of Option List
+--------+
|00000000|
+--------+
Kind=0
- 这个 option code 表示 option list 的结束
- 这不一定与 Data Offset field 所指示的 TCP header 结尾重合
- 用在所有 options 的末尾, 而不是每个 option 的末尾
- 只有当 options 的结尾不会以其他方式与 TCP header 的结尾重合时才需要
2. No-Operation
+--------+
|00000001|
+--------+
Kind=1
- 这个 option code 可以用在 options 之间
- 例如, 用于把后续 option 的起始位置对齐到 word boundary
- 不能保证发送方会使用此 option
- 接收方必须准备好处理不从 word boundary 开始的 options
3. Maximum Segment Size
+--------+--------+---------+--------+
|00000010|00000100| max seg size |
+--------+--------+---------+--------+
Kind=2 Length=4
Maximum Segment Size Option Data: 16 bits
- 如果存在此 option, 它会传达发送该 segment 的 TCP 的最大接收 segment size
- 此字段 must only be sent in the initial connection request (即设置 SYN control bit 的 segments)
- 如果不使用此 option, 则允许任意 segment size
MSS 说明 (MSS Notes):
- Default MSS = 536 bytes (Internet default)
- Common Ethernet MSS = 1460 bytes (1500 - 20 IP header - 20 TCP header)
- MSS 仅指数据部分, 不包括 TCP/IP headers
Padding: variable
TCP header padding 用于确保 TCP header 结束位置和 data 开始位置落在 32-bit boundary 上. Padding 由 zeros 组成.
3.2. 术语 (Terminology)
在讨论 TCP 的操作之前, 需要先引入一些详细术语. 维护一个 TCP connection 需要记住多个变量. 我们把这些变量设想为存储在一个称为 Transmission Control Block (TCB) 的连接记录中.
TCB 中存储的变量 (Variables Stored in TCB)
TCB 中存储的变量包括:
- 本地和远端 socket numbers
- 连接的 security 和 precedence
- 指向用户 send buffers 和 receive buffers 的指针
- 指向 retransmit queue 和 current segment 的指针
- 若干与发送和接收 sequence numbers 相关的变量
发送序列变量 (Send Sequence Variables)
| Variable | Full Name | 描述 (Description) |
|---|---|---|
| SND.UNA | Send Unacknowledged | 最旧的未确认 sequence number |
| SND.NXT | Send Next | 下一个要发送的 sequence number |
| SND.WND | Send Window | 发送窗口 |
| SND.UP | Send Urgent Pointer | 发送 urgent pointer |
| SND.WL1 | Segment Sequence Number | 上次 window update 使用的 segment sequence number |
| SND.WL2 | Segment Acknowledgment Number | 上次 window update 使用的 segment acknowledgment number |
| ISS | Initial Send Sequence Number | 初始发送 sequence number |
接收序列变量 (Receive Sequence Variables)
| Variable | Full Name | 描述 (Description) |
|---|---|---|
| RCV.NXT | Receive Next | 期望的下一个 sequence number |
| RCV.WND | Receive Window | 接收窗口 |
| RCV.UP | Receive Urgent Pointer | 接收 urgent pointer |
| IRS | Initial Receive Sequence Number | 初始接收 sequence number |
序列空间图 (Sequence Space Diagrams)
发送序列空间 (Send Sequence Space)
1 2 3 4
----------|----------|----------|----------
SND.UNA SND.NXT SND.UNA
+SND.WND
1 - old sequence numbers which have been acknowledged
2 - sequence numbers of unacknowledged data
3 - sequence numbers allowed for new data transmission
4 - future sequence numbers which are not yet allowed
发送窗口 (Send Window): 图中标记为 3 的 sequence space 部分
接收序列空间 (Receive Sequence Space)
1 2 3
----------|----------|----------
RCV.NXT RCV.NXT
+RCV.WND
1 - old sequence numbers which have been acknowledged
2 - sequence numbers allowed for new reception
3 - future sequence numbers which are not yet allowed
接收窗口 (Receive Window): 图中标记为 2 的 sequence space 部分
当前段变量 (Current Segment Variables)
这些变量来自 current segment 的字段:
| Variable | 描述 (Description) |
|---|---|
| SEG.SEQ | Segment sequence number |
| SEG.ACK | Segment acknowledgment number |
| SEG.LEN | Segment length |
| SEG.WND | Segment window |
| SEG.UP | Segment urgent pointer |
| SEG.PRC | Segment precedence value |
连接状态 (Connection States)
连接在其生命周期中会经过一系列状态. 这些状态是: LISTEN, SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT, 以及虚构状态 CLOSED.
状态说明 (State Descriptions)
| State | 描述 (Description) |
|---|---|
| LISTEN | 表示正在等待来自任意远端 TCP 和端口的连接请求 |
| SYN-SENT | 表示已经发送连接请求后, 正在等待匹配的连接请求 |
| SYN-RECEIVED | 表示已经收到并发送连接请求后, 正在等待确认连接请求的 acknowledgment |
| ESTABLISHED | 表示打开的连接, 接收到的数据可以交付给用户. 这是连接数据传输阶段的正常状态 |
| FIN-WAIT-1 | 表示正在等待来自远端 TCP 的连接终止请求, 或者等待对先前已发送连接终止请求的 acknowledgment |
| FIN-WAIT-2 | 表示正在等待来自远端 TCP 的连接终止请求 |
| CLOSE-WAIT | 表示正在等待来自本地用户的连接终止请求 |
| CLOSING | 表示正在等待来自远端 TCP 的连接终止请求 acknowledgment |
| LAST-ACK | 表示正在等待对先前发送给远端 TCP 的连接终止请求的 acknowledgment (该请求包含了对其连接终止请求的 acknowledgment) |
| TIME-WAIT | 表示正在等待足够长的时间, 以确保远端 TCP 收到了其连接终止请求的 acknowledgment |
| CLOSED | 表示完全没有连接状态 (虚构状态, 因为它表示不存在 TCB 时的状态) |
TCP Connection State Diagram
+---------+ ---------\ 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 Connection State Diagram
事件与状态转换 (Events and State Transitions)
TCP connection 会响应事件而从一个状态转换到另一个状态. 事件包括:
- User calls: OPEN, SEND, RECEIVE, CLOSE, ABORT, STATUS
- Arriving segments: 尤其是包含 SYN, ACK, RST 和 FIN flags 的 segments
- Timeouts: Retransmission timeout, TIME-WAIT timeout 等
注意 (Note): 该状态图只是摘要, 不能单独作为完整规范. 它只展示状态变化以及触发这些变化的事件和由此产生的动作, 但没有表示 error conditions, 也没有表示不与状态变化关联的动作.
3.3. 序列号 (Sequence Numbers)
基本概念 (Basic Concepts)
TCP 设计中的一个基本概念是, 通过 TCP connection 发送的每个数据 octet 都有一个 sequence number. 由于每个 octet 都被编号, 每个 octet 都可以被确认. 所使用的 acknowledgment mechanism 是累计的 (cumulative), 因此对 sequence number X 的 acknowledgment 表示 all octets up to but not including X have been received.
这种机制使得在发生 retransmission 时可以直接检测 duplicate. Segment 内 octets 的编号方式是: 紧跟 header 之后的第一个 data octet 具有最低编号, 后续 octets 连续编号.
序列号空间 (Sequence Number Space)
关键事实 (Key Fact): 实际 sequence number space 是有限的, 虽然非常大. 该空间范围为 0 到 2³² - 1.
模运算 (Modulo Arithmetic): 由于空间有限, 所有涉及 sequence numbers 的算术都必须按 modulo 2³² 执行. 这种无符号算术会在 sequence numbers 从 2³² - 1 循环回 0 时保持它们之间的关系. 计算机 modulo arithmetic 存在一些细微问题, 因此在编程比较这些值时必须格外小心.
记法约定 (Notation Convention):
- 符号
=<表示 "less than or equal" (modulo 2³²)
序列号比较 (Sequence Number Comparisons)
TCP 必须执行的典型 sequence number comparisons 包括:
- 确定某个 acknowledgment 指向已经发送但尚未确认的某个 sequence number
- 确定某个 segment 占用的所有 sequence numbers 都已经被确认 (例如, 用于从 retransmission queue 中移除该 segment)
- 确定传入 segment 是否包含期望的 sequence numbers (即该 segment 是否与 receive window "overlaps")
发送序列号处理 (Send Sequence Number Processing)
发送数据后, TCP 会收到 acknowledgments. 处理 acknowledgments 时需要以下比较:
SND.UNA = oldest unacknowledged sequence number
SND.NXT = next sequence number to be sent
SEG.ACK = acknowledgment from the receiving TCP (next sequence number expected by the receiving TCP)
SEG.SEQ = first sequence number of a segment
SEG.LEN = the number of octets occupied by the data in the segment (counting SYN and FIN)
SEG.SEQ+SEG.LEN-1 = last sequence number of a segment
可接受 ACK (Acceptable ACK):
新的 acknowledgment (称为 "acceptable ack") 需要满足下面的不等式:
SND.UNA < SEG.ACK ≤ SND.NXT
如果 retransmission queue 中某个 segment 的 sequence number 与 length 之和小于或等于传入 segment 中的 acknowledgment value, 则该 segment 已被完全确认.
示例 (Example):
SND.UNA = 1000 (oldest unacknowledged)
SND.NXT = 2000 (next to send)
Receive SEG.ACK = 1500
Check: 1000 < 1500 ≤ 2000 ✓ (acceptable)
Receive SEG.ACK = 2500
Check: 1000 < 2500 ≤ 2000 ✗ (not acceptable, acknowledges unsent data)
接收序列号处理 (Receive Sequence Number Processing)
接收数据时需要以下比较:
RCV.NXT = next sequence number expected on an incoming segment,
and is the left or lower edge of the receive window
RCV.NXT+RCV.WND-1 = last sequence number expected on an incoming segment,
and is the right or upper edge of the receive window
SEG.SEQ = first sequence number occupied by the incoming segment
SEG.SEQ+SEG.LEN-1 = last sequence number occupied by the incoming segment
Segment 可接受性测试 (Segment Acceptability Test)
只有当 segment 位于 window 内时, 才认为它是 acceptable. 测试取决于 segment length 和 window size:
| Segment Length | Window Size | Test for Acceptability |
|---|---|---|
| 0 | 0 | SEG.SEQ = RCV.NXT |
| 0 | >0 | RCV.NXT ≤ SEG.SEQ < RCV.NXT+RCV.WND |
| >0 | 0 | not acceptable |
| >0 | >0 | RCV.NXT ≤ SEG.SEQ < RCV.NXT+RCV.WND<br />or<br />RCV.NXT ≤ SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND |
说明 (Explanation):
- 针对 zero-length segments 的第一个测试可以看作测试一个 phantom segment, 它从 SEG.SEQ 开始但不占用任何 sequence space
- 如果 RCV.WND 为零, 则不接受任何数据, 但不占用空间的 segments 是 acceptable
实际代码示例 (Practical Code Example):
def is_segment_acceptable(seg_seq, seg_len, rcv_nxt, rcv_wnd):
"""Check if segment is acceptable"""
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:
# Either start or end of segment is within window
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
初始序列号选择 (Initial Sequence Number Selection, ISN)
Initial Sequence Number (ISN) 的选择非常关键. TCP 必须使用 clock-driven ISN generator, 以避免旧连接的 segments 被误认为是新连接的一部分.
ISN 生成建议 (ISN Generation Recommendations):
- ISN should be incremented by 1 every 4 microseconds
- ISN has a period of approximately 4.55 hours
- 新连接的 ISN 应当不同于旧连接的 ISN
安全考虑 (Security Considerations):
- 现代实现应当使用更安全的 ISN 生成算法 (RFC 6528)
- 防止 sequence number prediction attacks
关键概念总结 (Key Concepts Summary)
TCP 头部结构 (TCP Header Structure)
- 固定 20-byte header: 包含所有核心字段
- Variable-length options: 最多 40 bytes
- Checksum covers pseudo header: 提供额外的错误检测
序列号机制 (Sequence Number Mechanism)
- Per-byte numbering: 每个数据 byte 都有唯一的 sequence number
- Cumulative acknowledgment: Acknowledgment number 表示小于它的所有 bytes 都已收到
- Modulo 2³² arithmetic: Sequence number space 是循环的
连接状态 (Connection States)
- 11 states: 从 CLOSED 到 ESTABLISHED, 再回到 CLOSED
- Event-driven: User calls, segment arrivals, timeouts 触发状态转换
- Three-way handshake: SYN → SYN-ACK → ACK
- Four-way close: FIN → ACK → FIN → ACK
TCB 变量 (TCB Variables)
- Send variables: SND.UNA, SND.NXT, SND.WND 等
- Receive variables: RCV.NXT, RCV.WND 等
- Window management: 流量控制的核心
下一节 (Next Section): 3.4-3.9 连接管理与事件处理 (Connection Management & Event Processing) - 连接建立, 关闭, 数据通信和事件处理的详细规范