三次握手和四次挥手
TCP(传输控制协议)使用 三次握手(Three-way Handshake) 建立连接,使用 四次挥手(Four-way Handshake) 终止连接。这是保证可靠、面向连接通信的核心机制。
一、三次握手(建立连接)
目的:确保双方都具有发送和接收数据的能力,并同步初始序列号(Sequence Number)。
第一次握手(SYN):
- 客户端发送一个 TCP 报文段给服务器。
- 设置 SYN 标志位为 1(表示这是一个连接请求)。
- 选择一个初始序列号(Client_ISN)(通常是随机数)。
- 客户端进入
SYN_SENT
状态。
第二次握手(SYN + ACK):
- 服务器收到客户端的 SYN 报文。
- 如果同意建立连接,则发送一个 TCP 报文段给客户端。
- 设置 SYN 标志位为 1(表示这也是一个连接请求)。
- 设置 ACK 标志位为 1(表示确认)。
- 确认号(Acknowledgment Number) 设置为
Client_ISN + 1
(表示期望收到客户端的下一个字节的序号是这个值)。 - 选择一个自己的初始序列号(Server_ISN)(通常是随机数)。
- 服务器进入
SYN_RECEIVED
状态。
第三次握手(ACK):
- 客户端收到服务器的 SYN+ACK 报文。
- 客户端发送一个 TCP 报文段给服务器。
- 设置 ACK 标志位为 1(表示确认)。
- 确认号(Acknowledgment Number) 设置为
Server_ISN + 1
(表示期望收到服务器的下一个字节的序号是这个值)。 - (此时可以携带应用层数据)序列号为
Client_ISN + 1
(因为第一次握手的 SYN 消耗了一个序号)。 - 客户端进入
ESTABLISHED
状态。 - 服务器收到 ACK 后,也进入
ESTABLISHED
状态。
为什么需要三次?
- 防止旧的重复连接初始化请求造成混乱: 主要是为了防止在网络延迟的情况下,一个早已失效的连接请求报文突然又传到了服务器,导致服务器错误地打开连接(历史连接问题)。第三次握手让客户端有机会确认这个连接请求是否是当前最新的、有效的请求。
- 确保双方初始序列号同步: 第一次握手告知 Client_ISN,第二次握手确认 Client_ISN 并告知 Server_ISN,第三次握手确认 Server_ISN。只有双方都确认了对方的初始序列号,才能保证后续数据包传输的有序性。
- 验证双向通信能力: 第一次握手证明客户端能发送到服务器;第二次握手证明服务器能接收(收到第一次)并能发送到客户端;第三次握手证明客户端能接收(收到第二次)并能发送到服务器。
二、四次挥手(终止连接)
目的:双方都确认数据发送完毕,并安全、有序地关闭连接。TCP 连接是全双工的,每个方向必须独立关闭。
第一次挥手(FIN):
- 主动关闭方(可以是客户端或服务器,假设是客户端)发送一个 TCP 报文段。
- 设置 FIN 标志位为 1(表示它已经没有数据要发送了)。
- 指定一个序列号(假设为
Seq = u
),这个序列号等于它已传送数据的最后一个字节的序号加 1。 - 客户端进入
FIN_WAIT_1
状态。
第二次挥手(ACK):
- 被动关闭方(服务器)收到 FIN 报文。
- 发送一个 ACK 确认报文。
- 设置 ACK 标志位为 1。
- 确认号(Acknowledgment Number) 设置为
u + 1
(表示期望收到主动关闭方的下一个字节的序号是这个值)。 - (此时,服务器可能还有数据要发送给客户端)。
- 服务器进入
CLOSE_WAIT
状态。 - 客户端收到这个 ACK 后,进入
FIN_WAIT_2
状态(等待服务器的 FIN 报文)。
第三次挥手(FIN):
- 被动关闭方(服务器)完成了它所有数据的发送。
- 服务器发送一个 FIN 报文给主动关闭方(客户端)。
- 设置 FIN 标志位为 1。
- 指定一个序列号(假设为
Seq = w
),这个序列号等于它已传送数据的最后一个字节的序号加 1(可能包含在第二次挥手之后发送的数据)。 - 服务器进入
LAST_ACK
状态(等待最后一个 ACK)。
第四次挥手(ACK):
- 主动关闭方(客户端)收到服务器的 FIN 报文。
- 客户端发送一个 ACK 确认报文。
- 设置 ACK 标志位为 1。
- 确认号(Acknowledgment Number) 设置为
w + 1
。 - 客户端进入
TIME_WAIT
状态(也称为2MSL
等待状态)。 - 服务器收到这个 ACK 后,进入
CLOSED
状态(连接关闭)。 - 客户端在
TIME_WAIT
状态等待 2MSL(Maximum Segment Lifetime,报文最大生存时间,通常 1-4 分钟) 后,也进入CLOSED
状态。
为什么需要四次? 因为 TCP 连接是全双工的:
- 第一次挥手(FIN)表示“我(主动方)没有数据要发给你了”。
- 第二次挥手(ACK)表示“我知道你没数据发给我了”(此时被动方可能还有数据要发给主动方)。
- 第三次挥手(FIN)表示“我(被动方)也没有数据要发给你了”。
- 第四次挥手(ACK)表示“我知道你也没数据发给我了”,最终确认关闭。
为什么主动关闭方需要 TIME_WAIT 状态?
- 确保最后一个 ACK 可靠到达: 如果这个 ACK 丢失,被动关闭方(处于
LAST_ACK
)会超时重传 FIN。主动关闭方在TIME_WAIT
状态下收到重传的 FIN 后,会重新发送 ACK 并重置TIME_WAIT
计时器。 - 让旧连接的重复报文在网络中消逝: 等待 2MSL 时间,确保本次连接中产生的所有报文都已在网络中消失,不会干扰后续使用相同 IP 地址和端口号建立的新连接。
总结
- 三次握手: SYN -> SYN+ACK -> ACK。建立连接,确认双方通信能力和初始序列号。
- 四次挥手: FIN -> ACK -> FIN -> ACK。终止连接,双方独立确认数据发送完毕并关闭各自方向的通道。
这两个过程是 TCP 协议实现可靠传输、面向连接特性的基石。理解它们对于诊断网络问题和学习网络协议栈至关重要。