TCP/IP 三次握手与四次挥手:深入理解网络连接的建立与断开
详细讲解 TCP 协议的三次握手和四次挥手过程,包括状态转换、常见问题和实战抓包分析,帮助你彻底理解 TCP 连接机制
什么是 TCP 协议
TCP(Transmission Control Protocol,传输控制协议)是互联网协议族中最重要的传输层协议之一。它提供可靠的、面向连接的、字节流服务。
TCP 的核心特性
- 面向连接:通信前必须建立连接
- 可靠传输:保证数据按序到达,无丢失、无重复
- 流量控制:防止发送方发送过快导致接收方缓冲区溢出
- 拥塞控制:防止网络拥塞
- 全双工通信:双方可以同时发送和接收数据
TCP 三次握手(建立连接)
三次握手是 TCP 建立连接的过程,确保双方都准备好进行数据传输。
握手过程详解

第一次握手:客户端发送 SYN
客户端动作:
- 发送 SYN(同步序列号)报文段
- 设置 SYN=1,seq=x(随机初始序列号)
- 进入 SYN_SENT 状态
报文内容:
SYN = 1
seq = 1000(客户端初始序列号)
目的:告诉服务端"我想和你建立连接,我的初始序列号是 x"
第二次握手:服务端回应 SYN+ACK
服务端动作:
- 收到客户端的 SYN 后,发送 SYN+ACK 报文段
- 设置 SYN=1,ACK=1,seq=y,ack=x+1
- 进入 SYN_RCVD 状态
报文内容:
SYN = 1
ACK = 1
seq = 2000(服务端初始序列号)
ack = 1001(确认客户端的序列号+1)
目的:告诉客户端"我收到了你的请求,我也准备好了,我的初始序列号是 y,我确认了你的序列号"
第三次握手:客户端确认 ACK
客户端动作:
- 收到服务端的 SYN+ACK 后,发送 ACK 报文段
- 设置 ACK=1,ack=y+1
- 进入 ESTABLISHED 状态
报文内容:
ACK = 1
seq = 1001
ack = 2001(确认服务端的序列号+1)
目的:告诉服务端"我收到了你的确认,连接建立成功"
服务端动作:
- 收到客户端的 ACK 后,进入 ESTABLISHED 状态
- 连接建立完成,可以开始传输数据
为什么需要三次握手?
1. 防止旧连接请求导致混乱
场景:客户端发送的第一个 SYN 在网络中延迟了,客户端超时后重新发送了 SYN 并成功建立连接。后来,延迟的旧 SYN 到达服务端。
如果只有两次握手:
- 服务端收到旧 SYN,回复 SYN+ACK
- 服务端认为连接建立,开始等待数据
- 客户端不理会这个旧连接,导致服务端资源浪费
三次握手的优势:
- 服务端回复 SYN+ACK 后,等待客户端的第三次 ACK
- 客户端不会对旧连接发送 ACK
- 服务端超时后关闭连接,避免资源浪费
2. 确认双方的收发能力
- 第一次握手:服务端确认客户端的发送能力
- 第二次握手:客户端确认服务端的收发能力
- 第三次握手:服务端确认客户端的接收能力
3. 同步双方的初始序列号
TCP 是可靠传输,需要序列号来保证数据的顺序和完整性。三次握手确保双方都知道对方的初始序列号。
三次握手的状态转换
客户端状态:
CLOSED → SYN_SENT → ESTABLISHED
服务端状态:
CLOSED → LISTEN → SYN_RCVD → ESTABLISHED
TCP 四次挥手(断开连接)
四次挥手是 TCP 断开连接的过程,确保双方都完成数据传输。
挥手过程详解

第一次挥手:客户端发送 FIN
客户端动作:
- 发送 FIN(结束)报文段
- 设置 FIN=1,seq=u
- 进入 FIN_WAIT_1 状态
报文内容:
FIN = 1
seq = 5000
目的:告诉服务端"我没有数据要发送了,准备关闭连接"
注意:客户端仍然可以接收数据
第二次挥手:服务端确认 ACK
服务端动作:
- 收到客户端的 FIN 后,发送 ACK 报文段
- 设置 ACK=1,ack=u+1
- 进入 CLOSE_WAIT 状态
报文内容:
ACK = 1
ack = 5001
目的:告诉客户端"我收到了你的关闭请求,但我可能还有数据要发送,请等待"
客户端动作:
- 收到 ACK 后,进入 FIN_WAIT_2 状态
- 等待服务端发送 FIN
第三次挥手:服务端发送 FIN
服务端动作:
- 数据发送完毕后,发送 FIN 报文段
- 设置 FIN=1,seq=v
- 进入 LAST_ACK 状态
报文内容:
FIN = 1
seq = 6000
目的:告诉客户端"我的数据也发送完了,可以关闭连接了"
第四次挥手:客户端确认 ACK
客户端动作:
- 收到服务端的 FIN 后,发送 ACK 报文段
- 设置 ACK=1,ack=v+1
- 进入 TIME_WAIT 状态
- 等待 2MSL(Maximum Segment Lifetime)后关闭
报文内容:
ACK = 1
ack = 6001
目的:告诉服务端"我收到了你的关闭请求,连接可以关闭了"
服务端动作:
- 收到客户端的 ACK 后,进入 CLOSED 状态
- 连接完全关闭
为什么需要四次挥手?
1. TCP 是全双工通信
- 客户端发送 FIN,只是关闭了客户端到服务端的数据传输(半关闭)
- 服务端可能还有数据要发送给客户端
- 服务端发送完数据后,再发送 FIN 关闭服务端到客户端的数据传输
- 因此需要四次挥手来完全关闭双向连接
2. 为什么不能合并成三次?
第二次和第三次挥手不能合并的原因:
- 服务端收到客户端的 FIN 时,可能还有数据在发送
- 必须先 ACK 确认收到 FIN,然后继续发送数据
- 数据发送完毕后,再发送 FIN
特殊情况:如果服务端收到 FIN 时没有数据要发送,可以将 ACK 和 FIN 合并,变成三次挥手。
四次挥手的状态转换
主动关闭方(客户端)状态:
ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
被动关闭方(服务端)状态:
ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
TIME_WAIT 状态详解
为什么需要 TIME_WAIT?
1. 确保最后的 ACK 能够到达
- 如果客户端发送的最后一个 ACK 丢失,服务端会重传 FIN
- 客户端在 TIME_WAIT 状态可以重新发送 ACK
- 如果直接关闭,服务端重传的 FIN 会收到 RST,导致异常
2. 防止旧连接的数据包干扰新连接
- 等待 2MSL(通常是 2-4 分钟)确保网络中的旧数据包都消失
- 避免新连接收到旧连接的延迟数据包
2MSL 的含义:
- MSL(Maximum Segment Lifetime):报文段最大生存时间
- 2MSL = 报文段发送的最大时间 + 响应报文段返回的最大时间
TIME_WAIT 过多的问题:
- 占用端口资源(一个端口在 TIME_WAIT 期间不能被重用)
- 高并发场景下可能导致端口耗尽
解决方案:
# Linux 系统优化
# 允许 TIME_WAIT 状态的 socket 被重用
net.ipv4.tcp_tw_reuse = 1
# 快速回收 TIME_WAIT 状态的 socket
net.ipv4.tcp_tw_recycle = 1
# 减少 TIME_WAIT 超时时间
net.ipv4.tcp_fin_timeout = 30
实战:使用 tcpdump 抓包分析
抓取三次握手
# 抓取 80 端口的 TCP 连接
sudo tcpdump -i eth0 'tcp port 80' -nn -vv
# 输出示例:
# 第一次握手:SYN
# 12:00:00.000000 IP 192.168.1.100.50000 > 192.168.1.200.80: Flags [S], seq 1000, win 65535
# 第二次握手:SYN+ACK
# 12:00:00.001000 IP 192.168.1.200.80 > 192.168.1.100.50000: Flags [S.], seq 2000, ack 1001, win 65535
# 第三次握手:ACK
# 12:00:00.002000 IP 192.168.1.100.50000 > 192.168.1.200.80: Flags [.], ack 2001, win 65535
抓取四次挥手
# 抓取连接关闭过程
sudo tcpdump -i eth0 'tcp port 80 and (tcp[tcpflags] & tcp-fin != 0)' -nn -vv
# 输出示例:
# 第一次挥手:FIN
# 12:00:10.000000 IP 192.168.1.100.50000 > 192.168.1.200.80: Flags [F.], seq 5000, ack 6000
# 第二次挥手:ACK
# 12:00:10.001000 IP 192.168.1.200.80 > 192.168.1.100.50000: Flags [.], ack 5001
# 第三次挥手:FIN
# 12:00:10.002000 IP 192.168.1.200.80 > 192.168.1.100.50000: Flags [F.], seq 6000, ack 5001
# 第四次挥手:ACK
# 12:00:10.003000 IP 192.168.1.100.50000 > 192.168.1.200.80: Flags [.], ack 6001
TCP 状态机完整图
客户端状态转换:
CLOSED → SYN_SENT → ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
服务端状态转换:
CLOSED → LISTEN → SYN_RCVD → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
同时打开(罕见):
CLOSED → SYN_SENT → SYN_RCVD → ESTABLISHED
同时关闭(罕见):
ESTABLISHED → FIN_WAIT_1 → CLOSING → TIME_WAIT → CLOSED
总结
三次握手关键点
✅ 确保双方都准备好通信
✅ 同步双方的初始序列号
✅ 防止旧连接请求导致混乱
✅ 确认双方的收发能力
四次挥手关键点
✅ TCP 是全双工通信,需要双向关闭
✅ 被动关闭方可能还有数据要发送
✅ TIME_WAIT 确保连接可靠关闭
✅ 2MSL 等待时间防止旧数据包干扰
最佳实践
- 使用长连接:减少连接建立和关闭的开销
- 启用 Keep-Alive:防止连接被中间设备断开
- 优化系统参数:根据业务场景调整 TCP 参数
- 监控连接状态:及时发现和处理异常连接
- 使用连接池:复用连接,提高性能