第18章 TCP连接的建立与终止
所属:TCP/IP详解 卷1:协议 来源:TCP/IP详解 卷1:协议
本章介绍TCP连接的建立与终止,包括三次握手、四次挥手、TCP状态机、复位报文等。
18.1 引言
连接管理
TCP连接管理:
- 建立连接
- 终止连接
- 连接状态
- 各种异常处理
TCP是面向连接的,需要管理连接。
本章讨论的内容
本章讨论的内容:
- 三次握手(连接建立)
- 四次挥手(连接终止)
- TCP状态机
- 复位报文(RST)
- 半关闭
- 同时打开/同时关闭
- MSS选项
本章介绍TCP连接管理。
18.2 连接建立:三次握手
什么是三次握手
三次握手(Three-way Handshake):
- 建立TCP连接需要三次交互
- 双方确认对方的发送和接收能力
- 同步初始序号
三次握手建立连接。
三次握手的过程
三次握手的过程:
客户端 服务器
| |
| ---------- SYN -----------> | 1. 客户端发SYN
| seq=x | 同步,初始序号x
| |
| <------- SYN+ACK --------- | 2. 服务器发SYN+ACK
| seq=y, ack=x+1 | 同步自己的,确认客户端的
| |
| ---------- ACK -----------> | 3. 客户端发ACK
| seq=x+1, ack=y+1 | 确认服务器的
| |
| 连接建立了! |
三次握手:SYN → SYN+ACK → ACK。
为什么是三次
为什么是三次,不是两次?
-
确认双方的发送和接收能力
- 客户端发SYN:服务器知道客户端能发,自己能收
- 服务器发SYN+ACK:客户端知道服务器能收能发,自己能收能发
- 客户端发ACK:服务器知道客户端能收
-
防止旧的连接请求干扰
- 如果两次就建立
- 旧的SYN到了服务器
- 服务器就建立连接了
- 但客户端根本不想建立
- 浪费资源
-
同步初始序号
- 双方都要告诉对方自己的初始序号
- 双方都要确认对方的
- 三次刚好
三次握手是必要的。
初始序号
初始序号(ISN):
- 双方各自随机选择
- 不是从0开始
- 随时间变化
- 防止序号回绕和攻击
为什么随机:
- 安全
- 防止伪造
- 防止旧的分组干扰
初始序号是随机的。
MSS选项
MSS选项(Maximum Segment Size):
- 最大段大小
- TCP每次发的最大数据量
- 不包含TCP首部
- 在SYN段里协商
MSS和MTU的关系:
- MSS = MTU - IP首部 - TCP首部
- 以太网MTU=1500
- MSS = 1500 - 20 - 20 = 1460
为什么协商MSS:
- 避免分片
- 提高效率
- 双方知道对方能收多大的段
MSS在连接建立时协商。
18.3 连接终止:四次挥手
什么是四次挥手
四次挥手(Four-way Handshake):
- 关闭TCP连接需要四次交互
- 因为TCP是全双工的
- 两个方向要分别关闭
- 每个方向发一个FIN
四次挥手关闭连接。
四次挥手的过程
四次挥手的过程:
客户端 服务器
| |
| ---------- FIN -----------> | 1. 客户端发FIN
| seq=u | 我发完了
| |
| <---------- ACK ---------- | 2. 服务器发ACK
| ack=u+1 | 知道了
| |
| 客户端半关闭了,还能收 |
| |
| <---------- FIN ---------- | 3. 服务器发FIN
| seq=v | 我也发完了
| |
| ---------- ACK -----------> | 4. 客户端发ACK
| ack=v+1 | 知道了
| |
| 连接关闭了! |
四次挥手:FIN → ACK → FIN → ACK。
为什么是四次
为什么是四次?
- TCP是全双工的
- 两个方向独立
- 每个方向都要单独关闭
- 一个FIN关闭一个方向
- 所以需要两个FIN,每个都有ACK
- 总共四次
为什么三次握手的第二次可以合并:
- 建立连接时,SYN和ACK可以放一个包里
- 关闭时,FIN和ACK通常不能合并
- 因为收到FIN时,可能还有数据没发完
- 要先ACK,等数据发完了再FIN
因为全双工,所以四次。
半关闭
半关闭(Half-close):
- 一方发了FIN,进入半关闭状态
- 不能发了,但还能收
- 等对方也发FIN了才完全关闭
为什么需要半关闭:
- 客户端发完了,告诉服务器我发完了
- 但服务器可能还有数据要发
- 客户端还可以收
- 等服务器也发完了再关
半关闭可以收不能发。
18.4 TCP状态机
TCP状态
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,发了ACK,等待应用关闭 |
| CLOSING | 双方同时发FIN |
| LAST_ACK | 发了FIN,等待最后的ACK |
| TIME_WAIT | 收到FIN,发了ACK,等2MSL |
TCP有11个状态。
状态转换图
客户端的状态转换(主动打开):
CLOSED → SYN_SENT → ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
服务器的状态转换(被动打开):
CLOSED → LISTEN → SYN_RCVD → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
客户端和服务器的状态路径不同。
TIME_WAIT状态
TIME_WAIT状态:
- 主动关闭的一方最后进入的状态
- 等待2MSL时间
- 然后才到CLOSED
MSL:
- Maximum Segment Lifetime
- 最长分节生命期
- 一个TCP分段在网络上最长存活时间
- 通常是30秒、1分钟、2分钟
为什么需要TIME_WAIT:
-
保证最后的ACK能到达
- 最后一个ACK可能丢了
- 对方会重传FIN
- TIME_WAIT期间还能重发ACK
- 不然对方收不到ACK会一直重传
-
让旧的分组消失
- 防止这个连接的旧分组
- 干扰下一个同样的连接
- 等2MSL,旧的都死了
TIME_WAIT等2MSL。
2MSL等待
2MSL等待:
- TIME_WAIT的时间是2MSL
- 为什么是2倍?
- 一个方向最多MSL
- 两个方向就是2MSL
- 保证所有旧分组都消失
2MSL是最长的分组存活时间的两倍。
18.5 复位报文
什么是复位报文
复位报文(RST):
- RST标志位为1的段
- 复位连接
- 异常情况下用
- 不用四次挥手,直接复位
RST直接复位连接。
什么时候发RST
什么时候发RST:
-
连接不存在,收到数据
- 给一个没有的连接发数据
- 对方回RST
-
连接请求被拒绝
- 端口没开
- 服务器回RST
-
异常关闭连接
- 不想正常关闭
- 直接发RST
- 跳过TIME_WAIT
-
半开连接
- 一方以为连接还在
- 另一方已经关了
- 发数据就会收到RST
RST用于各种异常情况。
RST vs FIN
RST vs FIN:
| 对比项 | FIN | RST |
|---|---|---|
| 用途 | 正常关闭 | 异常复位 |
| 过程 | 四次挥手 | 一次就完 |
| 数据 | 缓冲区的数据会发完 | 直接丢 |
| 状态 | 有序关闭 | 强制关闭 |
| TIME_WAIT | 有 | 没有 |
FIN是正常关闭,RST是异常复位。
18.6 同时打开和同时关闭
同时打开
同时打开(Simultaneous Open):
- 双方同时主动打开
- 双方同时发SYN
- 比较少见
过程:
- 双方都发SYN
- 双方都收到SYN
- 双方都发SYN+ACK
- 双方都收到SYN+ACK
- 连接建立
状态转换:
- 两边都是SYN_SENT → SYN_RCVD → ESTABLISHED
同时打开比较少见。
同时关闭
同时关闭(Simultaneous Close):
- 双方同时主动关闭
- 双方同时发FIN
- 也比较少见
过程:
- 双方都发FIN
- 双方都收到FIN
- 双方都发ACK
- 双方都收到ACK
- 双方都进入CLOSING
- 然后TIME_WAIT
- 最后CLOSED
状态转换:
- 两边都是FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
同时关闭也比较少见。
18.7 小结
连接建立
-
三次握手
- SYN → SYN+ACK → ACK
- 三次交互
-
为什么三次
- 确认双方能力
- 防止旧连接干扰
- 同步初始序号
-
初始序号
- 随机选择
- 不是从0开始
-
MSS选项
- 最大段大小
- SYN里协商
- 避免分片
连接终止
-
四次挥手
- FIN → ACK → FIN → ACK
- 四次交互
-
为什么四次
- 全双工
- 两个方向分别关
- FIN和ACK不能合并
-
半关闭
- 发了FIN,不能发能收
- 等对方也FIN
TCP状态机
-
11个状态
- CLOSED, LISTEN
- SYN_SENT, SYN_RCVD
- ESTABLISHED
- FIN_WAIT_1, FIN_WAIT_2
- CLOSE_WAIT, CLOSING
- LAST_ACK, TIME_WAIT
-
客户端路径
- CLOSED → SYN_SENT → ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
-
服务器路径
- CLOSED → LISTEN → SYN_RCVD → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
TIME_WAIT
-
什么是TIME_WAIT
- 主动关闭最后等2MSL
- 然后才关闭
-
为什么需要
- 保证最后ACK到达
- 让旧分组消失
-
2MSL
- 最长分节生命期的两倍
- 保证所有旧分组都死了
复位报文
-
什么是RST
- 复位报文
- 直接复位连接
-
什么时候发
- 连接不存在
- 请求被拒绝
- 异常关闭
- 半开连接
-
vs FIN
- FIN正常关闭
- RST异常复位
同时打开/关闭
-
同时打开
- 双方同时发SYN
- 少见
-
同时关闭
- 双方同时发FIN
- CLOSING状态
- 少见
关键概念
-
三次握手
- 建立连接
- SYN, SYN+ACK, ACK
-
四次挥手
- 关闭连接
- FIN, ACK, FIN, ACK
-
TIME_WAIT
- 2MSL等待
- 两个原因
-
RST
- 复位连接
- 异常情况
-
状态机
- 11个状态
- 状态转换