目录
[一、TCP 三次握手](#一、TCP 三次握手)
[1.1 三次握手的目的](#1.1 三次握手的目的)
[1.2 三次握手流程](#1.2 三次握手流程)
[1.3 三次握手示意图](#1.3 三次握手示意图)
[二、TCP 四次挥手](#二、TCP 四次挥手)
[2.1 四次挥手的目的](#2.1 四次挥手的目的)
[2.2 四次挥手流程](#2.2 四次挥手流程)
[2.3 四次挥手示意图](#2.3 四次挥手示意图)
[3.1 为什么 TCP 建立连接是三次握手,而关闭连接是四次挥手?](#3.1 为什么 TCP 建立连接是三次握手,而关闭连接是四次挥手?)
[3.2 为什么 TCP 在四次挥手中要等待 2MSL?](#3.2 为什么 TCP 在四次挥手中要等待 2MSL?)
[3.3 为什么不能使用"两次握手"建立连接?](#3.3 为什么不能使用“两次握手”建立连接?)
在计算机网络中,TCP(传输控制协议)是一种面向连接、可靠的、基于字节流的传输层通信协议。它的核心目标是确保数据的可靠传输 ,即数据在复杂的网络环境中既不会丢失也不会乱序。为了实现这一点,TCP 设计了独特的三次握手 和四次挥手机制,确保连接的稳定性和数据的完整性。
本文将详细讲解 TCP 的三次握手和四次挥手过程,并深入探讨背后的原理及面试常见问题。
一、TCP 三次握手
1.1 三次握手的目的
TCP 的三次握手旨在确认双方的接收和发送能力,并协商好初始序列号(ISN),为数据传输做好准备。
1.2 三次握手流程
以下是三次握手的详细步骤:
第一步:客户端 → 服务器
- 客户端 发送一个带有
SYN
(同步序列号)标志的 TCP 报文段。 - 报文中包含客户端选择的初始序列号 (
client_isn
)。 - 此时,客户端进入
SYN_SENT
状态,表示客户端已发送连接请求,等待服务器响应。
第二步:服务器 → 客户端
- 服务器 收到客户端的
SYN
报文段后,向客户端发送一个SYN + ACK
报文段。 - 报文中包含:
- 服务器选择的初始序列号 (
server_isn
)。 - 对客户端 SYN 的确认号 (
client_isn + 1
)。
- 服务器选择的初始序列号 (
- 此时,服务器进入
SYN_RCVD
状态,表示服务器已收到客户端的连接请求并同意建立连接。
第三步:客户端 → 服务器
- 客户端 收到
SYN + ACK
报文后,向服务器发送一个ACK
报文段。 - 报文中包含:
- 确认号 为
server_isn + 1
(确认已收到服务器的SYN
报文)。 - 序列号 为
client_isn + 1
。
- 确认号 为
- 此时,客户端进入
ESTABLISHED
状态,表示连接已建立。 - 服务器收到 ACK 报文后,也进入
ESTABLISHED
状态。
至此,TCP 连接建立完成。
1.3 三次握手示意图
Lua
客户端 服务器
SYN (client_isn) --------> SYN_RCVD
SYN + ACK (server_isn) <-------- SYN_SENT
ACK (server_isn + 1) --------> ESTABLISHED

二、TCP 四次挥手
2.1 四次挥手的目的
TCP 的四次挥手用于安全地关闭连接,确保数据已传输完成,避免数据丢失。
2.2 四次挥手流程
以下是四次挥手的详细步骤:
第一次挥手:客户端 → 服务器
- 客户端 发送一个带有
FIN
(结束)标志的 TCP 报文段,表示客户端已经没有数据要发送,但仍可接收服务器的数据。 - 报文中包含序列号 (
client_seq
)。 - 此时,客户端进入
FIN_WAIT_1
状态。
第二次挥手:服务器 → 客户端
- 服务器 收到
FIN
报文段后,向客户端发送一个ACK
报文段确认收到FIN
。 - 报文中包含:
- 确认号 为
client_seq + 1
。 - 序列号 为
server_seq
。
- 确认号 为
- 此时,服务器进入
CLOSE_WAIT
状态,客户端进入FIN_WAIT_2
状态。
第三次挥手:服务器 → 客户端
- 当服务器确认所有数据已发送完毕时,向客户端发送一个
FIN
报文段,表示服务器也已准备好断开连接。 - 报文中包含序列号 为
server_seq + 1
。 - 此时,服务器进入
LAST_ACK
状态。
第四次挥手:客户端 → 服务器
- 客户端 收到
FIN
报文段后,发送一个ACK
报文段确认收到FIN
。 - 报文中包含:
- 确认号 为
server_seq + 2
。 - 序列号 为
client_seq + 1
。
- 确认号 为
- 客户端进入
TIME_WAIT
状态并等待一段时间(2MSL)后关闭。 - 服务器收到该
ACK
报文段后,进入CLOSED
状态。
2.3 四次挥手示意图
Lua
客户端 服务器
FIN (client_seq) --------> CLOSE_WAIT
ACK (client_seq + 1) <-------- FIN_WAIT_2
FIN (server_seq) <-------- LAST_ACK
ACK (server_seq + 2) --------> CLOSED

三、常见面试题解析
3.1 为什么 TCP 建立连接是三次握手,而关闭连接是四次挥手?
原因:
- 建立连接时,服务器可以将
SYN
和ACK
合并在一个报文中,减少一次通信。 - 关闭连接时,服务器可能还有未发送的数据,因此
FIN
和ACK
通常是分开发送的,从而多了一次挥手。
3.2 为什么 TCP 在四次挥手中要等待 2MSL?
**MSL(Maximum Segment Lifetime)**是一个数据包在网络中可能存活的最长时间。等待 2MSL 有以下两点原因:
-
确保服务器正确关闭连接:
- 若客户端的
ACK
报文在传输中丢失,服务器会在超时后重发FIN
报文。 - 客户端在 2MSL 内能接收到这个
FIN
并重新发送ACK
,确保服务器安全关闭。
- 若客户端的
-
防止已失效的数据包干扰新连接:
- 若客户端立刻关闭连接并重新发起新连接,之前网络中残留的旧数据包可能会被错误地当作新连接的数据,导致数据错乱。
- 2MSL 的等待时间可确保之前的连接数据包完全消失。
3.3 为什么不能使用"两次握手"建立连接?
两次握手存在以下风险:
- 若客户端的
SYN
包因网络延迟滞留在网络中,当客户端重新发送SYN
并成功建立连接后,之前滞留的SYN
包可能会再次到达服务器。 - 服务器会误以为这是新的连接请求,从而建立错误的连接,导致资源浪费或数据错乱。
四、总结
- 三次握手 是为了确认双方的收发能力 并协商初始序列号,确保数据传输的可靠性。
- 四次挥手是为了确保数据传输完成后再安全断开连接,避免数据丢失。
- 2MSL 等待机制保证了网络中的延迟数据包不会干扰新连接,是 TCP 保证可靠性的重要机制。
理解 TCP 的这些机制对网络编程、系统优化和面试应对至关重要。掌握这些知识,能够更好地理解 TCP 协议的精妙设计。