第22章 TCP:连接的建立与终止
所属:TCP/IP详解 卷2:实现 来源:TCP/IP详解 卷2:实现
本章描述TCP连接的建立与终止的实现,包括三次握手、四次挥手、TCP状态机和复位报文等。
22.1 引言
连接的建立和终止
TCP是面向连接的协议:
- 传输数据前要先建立连接
- 传输完要终止连接
- 连接的建立和终止都有规定的过程
连接管理是TCP的基本功能。
本章讨论的内容
本章讨论的内容:
- 连接建立(三次握手)
- 连接终止(四次挥手)
- TCP状态机
- 复位报文(RST)
- 同时打开和同时关闭
- 半关闭
本章讨论连接的建立和终止。
22.2 连接建立:三次握手
为什么需要三次握手
为什么需要三次握手:
-
同步序号
- 双方都要知道对方的初始序号
- 双方都要确认对方的序号
-
确认双方都有收发能力
- 客户端能发能收
- 服务端能发能收
-
防止旧的连接请求
- 防止迟到的连接请求
- 建立错误的连接
三次握手确保连接可靠建立。
三次握手的过程
三次握手(Three-Way Handshake):
客户端 服务端
| |
| ------ SYN -------> | 1. 客户端发SYN
| seq=x |
| |
| <--- SYN+ACK ---- | 2. 服务端回SYN+ACK
| seq=y, ack=x+1 |
| |
| ------ ACK -------> | 3. 客户端回ACK
| seq=x+1, ack=y+1 |
| |
+------ 连接建立 ------+ |
三个报文:
- SYN:客户端→服务端,请求连接
- SYN+ACK:服务端→客户端,同意连接,同步自己的序号
- ACK:客户端→服务端,确认服务端的序号
三次握手建立连接。
初始序号(ISN)
初始序号(Initial Sequence Number, ISN):
- 建立连接时的起始序号
- 不是从0开始
- 随机生成
- 随时间增长
为什么随机:
- 防止序号猜测攻击
- 防止旧的分组混淆
ISN是随机的,不是0。
MSS选项
MSS选项(Maximum Segment Size):
- 连接建立时协商
- 告诉对方自己最大能接收的段大小
- 通常是MTU - IP首部 - TCP首部
- 以太网通常是1460字节
为什么需要协商:
- 避免分片
- 提高效率
- 双方知道对方的MSS
MSS在连接建立时协商。
22.3 连接终止:四次挥手
为什么需要四次挥手
为什么需要四次挥手:
- TCP是全双工的
- 两个方向都要关闭
- 每个方向单独关闭
- 所以需要四次
全双工,两个方向都要关闭。
四次挥手的过程
四次挥手(Four-Way Handshake):
客户端 服务端
| |
| ------ FIN -------> | 1. 客户端发FIN,关闭客户端→服务端方向
| seq=u |
| |
| <----- ACK ------- | 2. 服务端回ACK
| seq=v, ack=u+1 |
| |
| <----- FIN ------- | 3. 服务端发FIN,关闭服务端→客户端方向
| seq=w |
| |
| ------ ACK -------> | 4. 客户端回ACK
| seq=u+1, ack=w+1 |
| |
+------ 连接终止 ------+ |
四个报文:
- FIN:主动关闭方发,关闭自己这个方向
- ACK:被动关闭方回,确认FIN
- FIN:被动关闭方发,关闭自己这个方向
- ACK:主动关闭方回,确认FIN
四次挥手终止连接。
半关闭
半关闭(Half-Close):
- 一个方向关闭了,另一个方向还开着
- 客户端发了FIN,服务端还能发数据
- 服务端发了FIN,客户端还能发数据
为什么需要:
- 客户端发完数据了,发FIN
- 服务端还有数据要发
- 可以继续发,发完再发FIN
半关闭允许单向关闭。
22.4 TCP状态机
11种状态
TCP的11种状态:
| 状态 | 说明 |
|---|---|
| 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 | 双方同时发FIN,等待ACK |
| LAST_ACK | 已发FIN+ACK,等待ACK |
| TIME_WAIT | 等待2MSL |
TCP有11种状态。
状态转换图
TCP状态转换图(简化):
+--------+
| CLOSED |
+--------+
| ^
passive open | | close
v |
+--------+
send | LISTEN | recv
SYN +--------+ SYN
| ^
v |
+-----------+ recv
send | SYN_SENT | SYN+ACK
SYN +-----------+ send
| | ACK
v |
+-----------+
recv | SYN_RCVD | send
ACK +-----------+ ACK
|
v
+-----------+
|ESTABLISHED|
+-----------+
| |
active close| |passive close
send FIN | |recv FIN
v v
+-----------+ +-----------+
|FIN_WAIT_1 | |CLOSE_WAIT |
+-----------+ +-----------+
| | |
recv | |recv |close
ACK | |FIN |send FIN
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 → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
被动打开+被动关闭:
CLOSED → LISTEN → SYN_RCVD → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
同时关闭:
ESTABLISHED → FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
不同的情况有不同的路径。
22.5 TIME_WAIT状态
为什么需要TIME_WAIT
TIME_WAIT状态:
- 主动关闭的最后状态
- 等待2MSL(Maximum Segment Lifetime)
- 然后才到CLOSED
为什么需要:
-
确保最后一个ACK到达
- 最后一个ACK可能丢
- 对端会重发FIN
- TIME_WAIT时还能重发ACK
- 不然对端一直重传
-
让旧的分组消失
- 防止旧连接的分组
- 被新连接当成新的
- 等2MSL,旧的都没了
两个原因:可靠关闭和防止混淆。
2MSL等待时间
2MSL等待时间:
- MSL:最大分节生命期
- 分组在网络中最长存活时间
- RFC建议2分钟
- 实际常用30秒到2分钟
- 2MSL就是1分钟到4分钟
为什么是2MSL:
- 一个方向最多MSL
- 另一个方向最多MSL
- 加起来2MSL
- 确保所有旧分组都消失
2MSL确保旧分组都消失。
TIME_WAIT的影响
TIME_WAIT的影响:
- 占用资源
- 短连接频繁的话,很多TIME_WAIT
- 可能耗尽端口
怎么处理:
- 正常现象,不用太担心
- 调整参数(如net.ipv4.tcp_tw_reuse)
- 长连接减少TIME_WAIT
TIME_WAIT是正常的,是TCP可靠性的保证。
22.6 复位报文(RST)
什么是复位报文
复位报文(Reset, RST):
- TCP的一种报文
- RST标志位为1
- 用于复位连接
- 表示错误或异常情况
RST用于异常情况。
什么时候发RST
发送RST的情况:
-
连接不存在
- 收到SYN,但没有监听的端口
- 发RST拒绝
-
连接异常
- 收到的报文不属于任何连接
- 发RST
-
异常关闭
- 应用异常关闭
- 发RST而不是FIN
-
半开连接
- 一端已经关了,另一端不知道
- 收到报文发RST
各种异常情况都可能发RST。
RST和FIN的区别
RST和FIN的区别:
| 对比项 | FIN | RST |
|---|---|---|
| 含义 | 正常关闭 | 异常复位 |
| 过程 | 四次挥手 | 直接复位 |
| 数据 | 缓冲区的数据会尽量发 | 直接丢弃 |
| 状态 | TIME_WAIT等 | 直接CLOSED |
| 用途 | 正常关闭 | 异常情况 |
FIN是正常关闭,RST是异常复位。
22.7 同时打开和同时关闭
同时打开
同时打开(Simultaneous Open):
- 双方同时发SYN
- 双方同时收到SYN
- 双方都发SYN+ACK
- 然后都收到SYN+ACK
- 连接建立
状态转换:
CLOSED → SYN_SENT → SYN_RCVD → ESTABLISHED
报文交换:
- 4个报文(两个SYN,两个SYN+ACK)
- 正常是3个
同时打开比较少见。
同时关闭
同时关闭(Simultaneous Close):
- 双方同时发FIN
- 双方同时收到FIN
- 双方都发ACK
- 然后都收到ACK
- 都进入TIME_WAIT
状态转换:
ESTABLISHED → FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
报文交换:
- 4个报文(两个FIN,两个ACK)
- 和正常的数量一样,只是顺序不同
同时关闭也比较少见。
22.8 小结
连接建立
-
三次握手
- SYN → SYN+ACK → ACK
- 同步序号
- 确认双方能力
-
初始序号
- 随机生成
- 不是0
- 防止攻击和混淆
-
MSS选项
- 协商最大段大小
- 避免分片
连接终止
-
四次挥手
- FIN → ACK → FIN → ACK
- 全双工,两个方向都关
-
半关闭
- 一个方向关了,另一个还开着
- 可以继续发数据
TCP状态机
-
11种状态
- CLOSED、LISTEN、SYN_SENT、SYN_RCVD
- ESTABLISHED
- FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT
- CLOSING、LAST_ACK、TIME_WAIT
-
状态转换
- 主动打开
- 被动打开
- 主动关闭
- 被动关闭
- 同时打开/关闭
TIME_WAIT
-
为什么需要
- 确保最后ACK到达
- 让旧分组消失
-
2MSL
- 最大分节生命期
- 等待2倍MSL
-
影响
- 占用资源
- 正常现象
复位报文
-
什么是RST
- 复位报文
- 异常情况用
-
什么时候发
- 连接不存在
- 连接异常
- 异常关闭
-
和FIN的区别
- FIN是正常关闭
- RST是异常复位
同时打开和关闭
-
同时打开
- 双方同时发SYN
- 4个报文
- 少见
-
同时关闭
- 双方同时发FIN
- 4个报文
- 少见
关键概念
-
三次握手
- 建立连接
- 同步序号
-
四次挥手
- 关闭连接
- 全双工
-
状态机
- 11种状态
- 各种转换
-
TIME_WAIT
- 2MSL等待
- 两个原因
-
RST
- 复位
- 异常情况