TCP三次握手和四次挥手

🔄 TCP 三次握手与四次挥手(全网最清晰版)

TCP 是面向连接的可靠传输协议,三次握手用于建立连接,四次挥手用于断开连接。下面我用图解 + 详细步骤 + 状态变化 + 面试重点,帮你彻底搞懂。


一、TCP 三次握手(建立连接)

📊 流程图

sequenceDiagram
    participant C as 客户端 (Client)
    participant S as 服务端 (Server)

    Note over C,S: 1. 第一次握手
    C->>S: SYN=1, seq=x
    Note over C: 状态:SYN_SENT

    Note over S: 状态:LISTEN → SYN_RCVD
    Note over C,S: 2. 第二次握手
    S->>C: SYN=1, ACK=1, seq=y, ack=x+1

    Note over C: 状态:SYN_SENT → ESTABLISHED
    Note over C,S: 3. 第三次握手
    C->>S: ACK=1, seq=x+1, ack=y+1

    Note over S: 状态:SYN_RCVD → ESTABLISHED
    Note over C,S: 连接建立成功

📝 详细步骤

步骤发送方 → 接收方报文内容发送方状态接收方状态
第一次客户端 → 服务端SYN=1, seq=xSYN_SENTLISTENSYN_RCVD
第二次服务端 → 客户端SYN=1, ACK=1, seq=y, ack=x+1SYN_SENTESTABLISHEDSYN_RCVD
第三次客户端 → 服务端ACK=1, seq=x+1, ack=y+1ESTABLISHEDSYN_RCVDESTABLISHED

🔍 关键字段解释

字段含义作用
SYN同步序列号发起一个新连接
ACK确认确认收到数据
seq序列号本报文的第一个字节的序号
ack确认号期望收到对方下一个报文的序列号

❓ 为什么是三次,不是两次或四次?

次数问题解释
两次❌ 无法确认客户端接收能力服务端发 SYN+ACK 后无法知道客户端是否收到
三次✅ 刚好确认双方收发能力1. 客户端发 SYN → 服务端知道客户端能发
2. 服务端回 SYN+ACK → 客户端知道自己能发能收,服务端能发
3. 客户端回 ACK → 服务端知道自己能发能收,客户端能收
四次❌ 浪费服务端的 SYN 和 ACK 可以合并一次发送

二、TCP 四次挥手(断开连接)

📊 流程图

📝 详细步骤

步骤发送方 → 接收方报文内容发送方状态接收方状态
第一次客户端 → 服务端FIN=1, seq=uESTABLISHEDFIN_WAIT_1ESTABLISHEDCLOSE_WAIT
第二次服务端 → 客户端ACK=1, seq=v, ack=u+1FIN_WAIT_1FIN_WAIT_2CLOSE_WAIT
第三次服务端 → 客户端FIN=1, ACK=1, seq=w, ack=u+1FIN_WAIT_2TIME_WAITCLOSE_WAITLAST_ACK
第四次客户端 → 服务端ACK=1, seq=u+1, ack=w+1TIME_WAIT (2MSL后 CLOSED)LAST_ACKCLOSED

🔑 关键状态解释

状态含义出现时机
FIN_WAIT_1主动方已发 FIN,等待 ACK第一次挥手后
FIN_WAIT_2主动方已收到 ACK,等待对方 FIN第二次挥手后
CLOSE_WAIT被动方收到 FIN,等待上层应用关闭第一次挥手后
LAST_ACK被动方已发 FIN,等待最后一个 ACK第三次挥手后
TIME_WAIT主动方收到 FIN,发完 ACK 后等待 2MSL第四次挥手后

❓ 为什么是四次,不是三次?

原因解释
TCP 是全双工双方都需要独立关闭自己的通道
数据可能未传完服务端收到 FIN 后可能还有数据要发,不能立即关
ACK 和 FIN 分开服务端的 ACK 只是确认收到 FIN,等数据发完再发自己的 FIN

⏱️ TIME_WAIT 为什么要等 2MSL?

原因解释
1. 确保最后一个 ACK 到达如果 ACK 丢失,服务端会重发 FIN,客户端还有时间响应
2. 防止旧报文干扰等待 2MSL 确保该连接的所有旧报文都已消失,不会干扰新连接

MSL:Maximum Segment Lifetime,报文最大生存时间,通常 30秒 – 2分钟


三、面试高频问题

Q1:为什么建立连接是三次握手,断开是四次挥手?

连接挥手
服务端可以合并 SYN 和 ACK服务端的 ACK 和 FIN 不能合并
因为建立连接时服务端没有数据要发因为断开时服务端可能还有数据要发

Q2:TIME_WAIT 过多怎么办?

# 查看 TIME_WAIT 数量
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

# 优化内核参数(/etc/sysctl.conf)
net.ipv4.tcp_tw_reuse = 1        # 允许重用 TIME_WAIT socket
net.ipv4.tcp_tw_recycle = 1       # 快速回收(NAT环境慎用)
net.ipv4.tcp_fin_timeout = 30     # FIN-WAIT-2 超时时间

# 生效
sysctl -p

Q3:CLOSE_WAIT 过多说明什么?

问题原因解决
CLOSE_WAIT 堆积应用程序没有正确调用 close()检查代码,确保 socket 用完关闭
常见于 Java/PHP 程序未捕获异常导致资源未释放lsof -p PID 查句柄数

Q4:如何抓包看三次握手?

tcpdump -i eth0 -nn port 80 -c 3 -w handshake.pcap
# 然后用 Wireshark 打开,Filter: tcp.flags.syn==1

📊 四、状态变化汇总表

角色握手状态变化挥手状态变化
客户端CLOSEDSYN_SENTESTABLISHEDESTABLISHEDFIN_WAIT_1FIN_WAIT_2TIME_WAITCLOSED
服务端LISTENSYN_RCVDESTABLISHEDESTABLISHEDCLOSE_WAITLAST_ACKCLOSED

✅ 五、一句话记忆法

过程记忆口诀
三次握手你听得到吗?我听到了,我也听得到
四次挥手我要关了 → 好的等我发完 → 我发完了 → 好的再见

需要我帮你分析抓包文件或排查实际连接问题吗?

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注