TCP三次握手与四次挥手深度解析 - SRE视角
SCQA结构
- 情境(Situation):作为SRE工程师,网络故障排查是日常工作的重要组成部分,而TCP协议是互联网的基础协议之一
- 冲突(Conflict):TCP协议的三次握手和四次挥手过程复杂,字段含义丰富,实际网络抓包中可能出现与理论不符的情况
- 问题(Question):如何从SRE视角深入理解TCP三次握手和四次挥手的全流程?如何解释实际抓包中的异常情况?
- 答案(Answer):本文将结合实际tcpdump抓包结果,详细解析TCP三次握手和四次挥手的每一个字段含义,并分析常见异常情况
一、TCP协议基础
TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层协议。它通过三次握手建立连接,四次挥手关闭连接,使用序号和确认机制保证数据的可靠传输。
二、实际抓包分析
我们先来看一段实际的tcpdump抓包结果:
19:49:11 root@rocky9.6-12,10.0.0.52:~ # tcpdump -Si ens160 -nn tcp and ip host 10.0.0.31 and 10.0.0.12
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens160, link-type EN10MB (Ethernet), snapshot length 262144 bytes
19:49:25.404687 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [S], seq 2595890315, win 64240, options [mss 1460,sackOK,TS val 2913276518 ecr 0,nop,wscale 7], length 0
19:49:25.404715 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [S.], seq 1389065622, ack 2595890316, win 65160, options [mss 1460,sackOK,TS val 65980928 ecr 2913276518,nop,wscale 7], length 0
19:49:25.404933 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [.], ack 1389065623, win 502, options [nop,nop,TS val 2913276518 ecr 65980928], length 0
19:49:25.404934 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [P.], seq 2595890316:2595890388, ack 1389065623, win 502, options [nop,nop,TS val 2913276518 ecr 65980928], length 72: HTTP: GET / HTTP/1.1
19:49:25.404952 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [.], ack 2595890388, win 509, options [nop,nop,TS val 65980928 ecr 2913276518], length 0
19:49:25.405284 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [P.], seq 1389065623:1389066076, ack 2595890388, win 509, options [nop,nop,TS val 65980928 ecr 2913276518], length 453: HTTP: HTTP/1.1 200 OK
19:49:25.405658 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [.], ack 1389066076, win 501, options [nop,nop,TS val 2913276519 ecr 65980928], length 0
19:49:25.405658 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [F.], seq 2595890388, ack 1389066076, win 501, options [nop,nop,TS val 2913276519 ecr 65980928], length 0
19:49:25.405726 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [F.], seq 1389066076, ack 2595890389, win 509, options [nop,nop,TS val 65980929 ecr 2913276519], length 0
19:49:25.405943 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [.], ack 1389066077, win 501, options [nop,nop,TS val 2913276519 ecr 65980929], length 0
三、TCP三次握手详细解析
TCP三次握手是建立连接的过程,用于确保双方都准备好进行数据传输,并就初始序列号达成一致。
1. 第一次握手(客户端→服务器)
19:49:25.404687 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [S], seq 2595890315, win 64240, options [mss 1460,sackOK,TS val 2913276518 ecr 0,nop,wscale 7], length 0
字段解析:
- 时间戳:19:49:25.404687 - 数据包捕获时间
- 源IP和端口:10.0.0.31.42124 - 客户端IP和随机端口
- 目的IP和端口:10.0.0.12.80 - 服务器IP和HTTP服务端口
- Flags [S]:SYN标志位,表示发起连接请求
- seq 2595890315:客户端初始序列号(ISN),用于标识后续发送的数据字节流
- win 64240:客户端接收窗口大小,表示客户端缓冲区可用空间
- options:
- mss 1460:最大报文段大小,TCP报文数据部分的最大长度
- sackOK:支持选择性确认
- TS val 2913276518 ecr 0:时间戳选项,val是客户端时间戳,ecr是回显的服务器时间戳(此处为0表示首次握手)
- nop:无操作,用于对齐
- wscale 7:窗口缩放因子,实际窗口大小 = win × 2^wscale
- length 0:数据部分长度为0,因为这只是连接请求
2. 第二次握手(服务器→客户端)
19:49:25.404715 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [S.], seq 1389065622, ack 2595890316, win 65160, options [mss 1460,sackOK,TS val 65980928 ecr 2913276518,nop,wscale 7], length 0
字段解析:
- Flags [S.]:SYN+ACK标志位,S表示同意建立连接,.表示ACK确认
- seq 1389065622:服务器初始序列号(ISN)
- ack 2595890316:确认号,等于客户端ISN+1,表示已收到客户端的SYN请求
- win 65160:服务器接收窗口大小
- options:
- TS val 65980928 ecr 2913276518:服务器时间戳,ecr回显客户端第一次握手的时间戳
3. 第三次握手(客户端→服务器)
19:49:25.404933 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [.], seq 2595890316, ack 1389065623, win 502, options [nop,nop,TS val 2913276518 ecr 65980928], length 0
字段解析:
- Flags [.]:ACK标志位,仅表示确认
- seq 2595890316:客户端序列号,等于第一次握手的ISN+1
- ack 1389065623:确认号,等于服务器ISN+1,表示已收到服务器的SYN+ACK响应
三次握手完成:此时TCP连接已建立,双方可以开始传输数据。
四、数据传输过程
在三次握手之后,客户端和服务器开始进行数据传输:
1. 客户端发送HTTP请求
19:49:25.404934 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [P.], seq 2595890316:2595890388, ack 1389065623, win 502, options [nop,nop,TS val 2913276518 ecr 65980928], length 72: HTTP: GET / HTTP/1.1
字段解析:
- Flags [P.]:PSH+ACK标志位,PSH表示推送数据,.表示ACK确认
- seq 2595890316:2595890388:数据序列号范围,表示发送的数据字节范围
- length 72:数据部分长度为72字节,包含HTTP GET请求
2. 服务器确认收到请求
19:49:25.404952 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [.], ack 2595890388, win 509, options [nop,nop,TS val 65980928 ecr 2913276518], length 0
字段解析:
- ack 2595890388:确认号等于客户端发送的最后一个字节序列号+1,表示已收到所有请求数据
3. 服务器发送HTTP响应
19:49:25.405284 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [P.], seq 1389065623:1389066076, ack 2595890388, win 509, options [nop,nop,TS val 65980928 ecr 2913276518], length 453: HTTP: HTTP/1.1 200 OK
字段解析:
- seq 1389065623:1389066076:服务器发送的数据序列号范围
- length 453:数据部分长度为453字节,包含HTTP 200响应
4. 客户端确认收到响应
19:49:25.405658 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [.], ack 1389066076, win 501, options [nop,nop,TS val 2913276519 ecr 65980928], length 0
字段解析:
- ack 1389066076:确认号等于服务器发送的最后一个字节序列号+1,表示已收到所有响应数据
五、TCP四次挥手详细解析
TCP四次挥手是关闭连接的过程,用于确保双方都已完成数据传输,并释放资源。
1. 第一次挥手(客户端→服务器)
19:49:25.405658 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [F.], seq 2595890388, ack 1389066076, win 501, options [nop,nop,TS val 2913276519 ecr 65980928], length 0
字段解析:
- Flags [F.]:FIN+ACK标志位,FIN表示客户端不再发送数据,.表示ACK确认
- seq 2595890388:客户端最后发送的数据序列号
- ack 1389066076:确认服务器已发送的数据
2. 第二次挥手(服务器→客户端)
19:49:25.405726 IP 10.0.0.12.80 > 10.0.0.31.42124: Flags [F.], seq 1389066076, ack 2595890389, win 509, options [nop,nop,TS val 65980929 ecr 2913276519], length 0
字段解析:
- Flags [F.]:FIN+ACK标志位,服务器同时发送FIN和ACK
- seq 1389066076:服务器最后发送的数据序列号
- ack 2595890389:确认客户端的FIN请求
3. 第三次挥手(客户端→服务器)
19:49:25.405943 IP 10.0.0.31.42124 > 10.0.0.12.80: Flags [.], seq 2595890389, ack 1389066077, win 501, options [nop,nop,TS val 2913276519 ecr 65980929], length 0
字段解析:
- Flags [.]:ACK标志位,客户端确认服务器的FIN请求
- seq 2595890389:客户端序列号,等于第一次挥手的FIN序列号+1
- ack 1389066077:确认号,等于服务器FIN序列号+1
六、常见四次挥手流程与异常分析
1. 常见四次挥手流程
标准四次挥手流程:
- 客户端发送FIN,请求关闭连接 → FIN_WAIT_1状态
- 服务器发送ACK,确认收到FIN → 客户端进入FIN_WAIT_2状态,服务器进入CLOSE_WAIT状态
- 服务器发送FIN,请求关闭连接 → 服务器进入LAST_ACK状态
- 客户端发送ACK,确认收到FIN → 客户端进入TIME_WAIT状态,服务器进入CLOSED状态
- 客户端等待2MSL(最大报文段寿命)后进入CLOSED状态
2. 抓包中的异常分析
用户疑问:观测到四次挥手并没有像正常的客户端发起FIN标志,而是服务器段发起的ACK标志,这是为何?
实际情况分析:
- 从抓包结果看,客户端确实先发起了FIN标志(第一次挥手):
Flags [F.] - 服务器的响应是同时发送了FIN和ACK标志(第二次挥手):
Flags [F.] - 这是一种优化的四次挥手,服务器在收到客户端的FIN后,立即发送FIN+ACK,将第二次和第三次挥手合并为一次
为什么会出现这种情况?
- 当服务器在收到客户端FIN时,已经没有更多数据要发送给客户端
- 服务器可以直接发送FIN+ACK,减少一次网络往返,提高效率
- 这种情况在HTTP/1.0短连接中很常见,服务器处理完请求后立即关闭连接
3. 四次挥手各阶段状态变化
| 阶段 | 客户端状态 | 服务器状态 | 操作 |
|---|---|---|---|
| 1 | FIN_WAIT_1 | ESTABLISHED | 客户端发送FIN |
| 2 | FIN_WAIT_2 | CLOSE_WAIT | 服务器发送ACK |
| 3 | FIN_WAIT_2 | LAST_ACK | 服务器发送FIN |
| 4 | TIME_WAIT | CLOSED | 客户端发送ACK |
| 5 | CLOSED | - | 客户端等待2MSL后关闭 |
七、SRE视角的TCP故障排查要点
1. 三次握手故障
- SYN丢失:客户端持续重传SYN,但无响应,可能是网络问题或服务器过载
- SYN_RCVD堆积:服务器大量连接处于SYN_RCVD状态,可能遭遇SYN洪水攻击
- 半连接状态:客户端或服务器长时间处于SYN_SENT或SYN_RCVD状态,可能是防火墙配置问题
2. 四次挥手故障
- TIME_WAIT过多:客户端大量连接处于TIME_WAIT状态,可能是短连接过多导致,可调整tcp_tw_reuse、tcp_tw_recycle等参数
- CLOSE_WAIT过多:服务器大量连接处于CLOSE_WAIT状态,可能是应用程序未正确关闭连接
- FIN_WAIT_2过多:客户端大量连接处于FIN_WAIT_2状态,可能是服务器未发送FIN,需检查服务器应用
3. 常用排查命令
# 查看TCP连接状态
ss -tuln
ss -tan state TIME_WAIT
# 查看TCP相关内核参数
sysctl -a | grep tcp
# 抓包并分析
tcpdump -i eth0 -nn tcp port 80
wireshark # 图形化分析工具
八、结论
TCP三次握手和四次挥手是确保可靠连接的核心机制,作为SRE工程师,深入理解其原理和字段含义对于网络故障排查至关重要。实际网络中,TCP协议会根据具体情况进行优化,如合并挥手包,这是正常现象。
通过分析tcpdump抓包结果,我们可以:
- 确认连接建立和关闭的完整性
- 定位网络延迟和丢包问题
- 识别异常连接状态
- 优化TCP参数配置
掌握TCP协议的底层原理,将帮助我们更好地设计和维护可靠的网络服务。
文档信息
- 本文作者:soveran zhong
- 本文链接:https://blog.clockwingsoar.cyou/2025/12/01/tcp-three-way-handshake-four-way-wave/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)