第16章 TCP:传输控制协议
所属:TCP/IP详解 卷2:实现 来源:TCP/IP详解 卷2:实现
本章描述TCP协议的基本实现,包括TCP首部、TCP控制块、TCP状态机、TCP输入和输出的基本框架。
16.1 引言
TCP的特点
TCP(Transmission Control Protocol):
- 传输控制协议
- 面向连接
- 可靠交付
- 保证顺序
- 流量控制
- 拥塞控制
- 全双工
TCP是可靠的面向连接的传输层协议。
TCP的复杂性
TCP为什么复杂:
- 要保证可靠
- 要处理拥塞
- 要处理流量控制
- 要处理各种异常情况
- 状态很多
- 定时器很多
TCP比UDP复杂得多。
本章讨论的内容
本章讨论的内容:
- TCP首部格式
- TCP控制块(tcpcb)
- TCP状态机
- TCP输入处理(tcp_input)
- TCP输出处理(tcp_output)
- TCP定时器概述
本章是TCP部分的概述。
16.2 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口 | 目的端口 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 序号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 确认号 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|首部长度| 保留 |U|A|P|R|S|F| 窗口大小 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 检验和 | 紧急指针 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 选项(如果有) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据(如果有) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段说明
| 字段 | 大小 | 说明 |
|---|---|---|
| 源端口 | 16位 | 发送方端口号 |
| 目的端口 | 16位 | 接收方端口号 |
| 序号 | 32位 | 本报文段数据的第一个字节的序号 |
| 确认号 | 32位 | 期望收到的下一个字节的序号 |
| 首部长度 | 4位 | 首部长度,以4字节为单位 |
| 保留 | 6位 | 保留,必须为0 |
| URG | 1位 | 紧急指针有效 |
| ACK | 1位 | 确认号有效 |
| PSH | 1位 | 推送操作 |
| RST | 1位 | 复位连接 |
| SYN | 1位 | 同步序号 |
| FIN | 1位 | 发送方完成发送 |
| 窗口大小 | 16位 | 接收窗口大小(流量控制) |
| 检验和 | 16位 | TCP首部+数据的检验和 |
| 紧急指针 | 16位 | 紧急数据的最后一个字节的偏移 |
| 选项 | 可变 | 可选,如MSS、窗口扩大、时间戳等 |
TCP首部最小20字节,选项最多40字节。
tcphdr结构
内核中的TCP首部结构:
struct tcphdr {
u_short th_sport; /* 源端口 */
u_short th_dport; /* 目的端口 */
u_int th_seq; /* 序号 */
u_int th_ack; /* 确认号 */
u_char th_x2:4; /* 保留 */
u_char th_off:4; /* 首部长度 */
u_char th_flags; /* 标志位 */
u_short th_win; /* 窗口大小 */
u_short th_sum; /* 检验和 */
u_short th_urp; /* 紧急指针 */
};对应TCP首部的C结构。
标志位
TCP标志位:
| 标志 | 名称 | 说明 |
|---|---|---|
| URG | 紧急 | 紧急指针有效 |
| ACK | 确认 | 确认号有效 |
| PSH | 推送 | 立即推送 |
| RST | 复位 | 复位连接 |
| SYN | 同步 | 同步序号,建立连接 |
| FIN | 结束 | 发送完成,关闭连接 |
每个标志位有不同的作用。
16.3 TCP控制块
tcpcb结构
TCP控制块(tcpcb):
struct tcpcb {
struct inpcb t_inpcb; /* 通用PCB,必须是第一个 */
/* 序号相关 */
u_int t_seq; /* 发送下一个序号 */
u_int t_una; /* 发送未确认的第一个序号 */
u_int t_rack; /* 最近收到的ACK */
u_int t_rcv_nxt; /* 接收下一个序号 */
u_int t_rcv_adv; /* 接收窗口通告 */
/* 窗口相关 */
u_int t_snd_wnd; /* 发送窗口大小 */
u_int t_rcv_wnd; /* 接收窗口大小 */
u_int t_snd_cwnd; /* 拥塞窗口大小 */
u_int t_snd_ssthresh; /* 慢启动阈值 */
/* 状态 */
int t_state; /* 连接状态 */
int t_flags; /* 各种标志 */
/* 定时器 */
int t_timer[TCPT_NTIMERS]; /* 定时器 */
int t_rxtcur; /* 当前重传超时 */
/* RTT测量 */
int t_srtt; /* 平滑RTT */
int t_rttvar; /* RTT方差 */
int t_rttseq; /* RTT测量的序号 */
int t_rtt; /* 当前RTT */
/* 其他 */
int t_maxseg; /* 最大段大小 */
int t_softerror; /* 软错误 */
/* ... 还有很多字段 ... */
};关键字段说明
| 字段 | 说明 |
|---|---|
| t_inpcb | 通用inpcb,第一个成员,可以强制转换 |
| t_seq | 下一个要发送的字节序号 |
| t_una | 已发送但未确认的第一个字节的序号 |
| t_rcv_nxt | 期望收到的下一个字节的序号 |
| t_snd_wnd | 发送窗口(对端通告的) |
| t_rcv_wnd | 接收窗口(自己的) |
| t_snd_cwnd | 拥塞窗口(拥塞控制用) |
| t_snd_ssthresh | 慢启动阈值 |
| t_state | 连接状态(CLOSED、ESTABLISHED等) |
| t_timer | 各种定时器 |
| t_srtt / t_rttvar | RTT估计值和方差 |
| t_maxseg | 最大段大小(MSS) |
tcpcb包含TCP连接的所有状态。
t_state状态
TCP连接状态:
| 状态 | 说明 |
|---|---|
| CLOSED | 关闭,没有连接 |
| LISTEN | 监听,等待连接 |
| SYN_SENT | 已发SYN,等待SYN+ACK |
| SYN_RCVD | 已收SYN,已发SYN+ACK,等待ACK |
| ESTABLISHED | 已建立连接,可以传输数据 |
| FIN_WAIT_1 | 已发FIN,等待ACK |
| FIN_WAIT_2 | 已收FIN的ACK,等待对端FIN |
| CLOSE_WAIT | 已收FIN,等待应用关闭 |
| CLOSING | 双方同时关闭,等待ACK |
| LAST_ACK | 已发FIN+ACK,等待ACK |
| TIME_WAIT | 等待2MSL |
TCP有11种状态。
16.4 TCP状态机
TCP状态转换图
TCP状态机:
+---------+
send | LISTEN | recv
SYN +---------+ SYN
| ^
v |
+---------+ |
send |SYN_SENT | recv
SYN +---------+ SYN+ACK
| |
v |
+---------+ |
recv |SYN_RCVD | send
ACK +---------+ ACK
|
v
+---------+
|ESTABLISHED|
+---------+
|
v
+-----------+
send |FIN_WAIT_1 | recv
FIN +-----------+ ACK
| | |
recv FIN | | | recv FIN+ACK
v v v
+-----------+ +-----------+
|FIN_WAIT_2 | | CLOSING |
+-----------+ +-----------+
| |
recv | recv |
FIN | ACK |
v v
+-----------+ +-----------+
|TIME_WAIT | | LAST_ACK |
+-----------+ +-----------+
| |
2MSL | recv |
超时 | ACK |
v v
CLOSED
这是简化的状态转换图。
状态转换说明
主要的状态转换:
-
主动打开
- CLOSED → SYN_SENT → ESTABLISHED
-
被动打开
- CLOSED → LISTEN → SYN_RCVD → ESTABLISHED
-
主动关闭
- ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
-
被动关闭
- ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
-
同时关闭
- ESTABLISHED → FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
不同的情况有不同的转换路径。
16.5 TCP输入处理
tcp_input函数
TCP输入处理(tcp_input):
- IP层分用后调用
- 处理收到的TCP段
- 验证TCP首部
- 查找对应的PCB
- 根据状态处理
- 可能发送应答
- 可能更新状态
tcp_input是TCP输入的入口,很复杂。
输入处理的步骤
TCP输入处理的大致步骤:
-
验证
- 验证长度
- 验证校验和
-
查找PCB
- 根据源目地址和端口查找
- 找最匹配的
-
根据状态处理
- LISTEN状态:处理连接请求
- SYN_SENT状态:处理SYN+ACK
- ESTABLISHED状态:处理数据和ACK
- 等等
-
处理数据
- 按序号排序
- 放入接收缓冲区
- 发送ACK
-
处理ACK
- 确认发送的数据
- 更新窗口
- 可能触发重传定时器调整
tcp_input很复杂,要处理各种情况。
16.6 TCP输出处理
tcp_output函数
TCP输出处理(tcp_output):
- 发送TCP段
- 构造TCP首部
- 计算校验和
- 调用IP层发送
- 启动重传定时器
tcp_output是TCP输出的入口。
什么时候调用tcp_output
调用tcp_output的时机:
- 应用发送数据
- 收到ACK需要发送新数据
- 重传定时器超时
- 坚持定时器超时
- 需要发送ACK
- 需要发送窗口更新
- 等等
很多情况都会触发输出。
16.7 TCP定时器
TCP的定时器
TCP有多个定时器:
-
重传定时器(retransmission timer)
- 发送数据后启动
- 超时没收到ACK就重传
-
坚持定时器(persist timer)
- 窗口为0时启动
- 周期性探查窗口
-
保活定时器(keepalive timer)
- 空闲连接的探查
- 可选
-
2MSL定时器
- TIME_WAIT状态
- 等待2MSL后关闭
TCP有多个定时器,各有各的作用。
16.8 小结
TCP概述
-
特点
- 面向连接
- 可靠交付
- 保证顺序
- 流量控制
- 拥塞控制
- 全双工
-
复杂性
- 状态多
- 定时器多
- 处理各种情况
TCP首部
-
格式
- 源端口、目的端口
- 序号、确认号
- 首部长度、标志位
- 窗口大小、检验和、紧急指针
- 选项
-
标志位
- URG、ACK、PSH、RST、SYN、FIN
-
长度
- 最小20字节
- 选项最多40字节
TCP控制块
-
tcpcb结构
- t_inpcb:通用PCB
- 序号相关字段
- 窗口相关字段
- 状态
- 定时器
- RTT估计
- 等等
-
状态
- 11种状态
- CLOSED到TIME_WAIT
TCP状态机
-
状态转换
- 主动打开
- 被动打开
- 主动关闭
- 被动关闭
- 同时关闭
-
TIME_WAIT
- 等待2MSL
- 确保最后一个ACK到达
TCP输入输出
-
tcp_input
- 输入入口
- 验证、查找PCB
- 按状态处理
- 处理数据和ACK
-
tcp_output
- 输出入口
- 构造段
- 调用IP发送
TCP定时器
-
重传定时器
- 超时重传
-
坚持定时器
- 窗口探查
-
保活定时器
- 空闲探查
-
2MSL定时器
- TIME_WAIT
关键概念
-
TCP
- 可靠的面向连接协议
- 复杂但强大
-
tcpcb
- TCP控制块
- 包含所有状态
-
状态机
- 11种状态
- 各种转换
-
tcp_input / tcp_output
- 输入输出入口
- 核心函数
-
定时器
- 多个定时器
- 各有用途