真实面经题目 · 原创解析

TCP断开时有4次交互,而连接时有3次交互,多出来的一次是在做什么事情呢?

TCP 连接建立只需要双方确认彼此的发送能力和接收能力,因此三次握手即可完成双向能力确认;TCP 连接断开面对的是全双工连接的两个方向分别关闭,FIN 只表示一端不再发送数据,对端必须先 ACK 确认,等自己也没有数据要发送后再发 FIN。

出现于:阿里巴巴 · 后端开发

60 秒回答模板

可以这样回答:TCP 连接是全双工的,建立连接时三次握手是为了确认双方的收发能力和初始序列号;但断开连接时,两个方向的数据流要分别关闭。主动关闭方发送 FIN 表示“我这边没有数据要发了”,被动关闭方收到后要立即返回 ACK,表示“我知道你不发了”。不过被动关闭方此时不一定也没有数据要发,它可能还要等应用层处理完、把剩余数据发送完,之后才发送自己的 FIN。主动关闭方再 ACK 确认这个 FIN。多出来的一次就是被动关闭方的 FIN 不能总是和 ACK 合并,因为 ACK 是 TCP 内核对收到 FIN 的确认,而 FIN 代表本端应用也决定关闭发送方向,这两个事件在时间上可能不同时发生。状态上对应主动方进入 FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT,被动方进入 CLOSE_WAIT、LAST_ACK。某些情况下 ACK 和 FIN 可以合并成一个报文,但概念上仍然是两个动作。

考点 目标不同
主线 FIN 的含义
易错点 误以为 FIN 表示整个连接马上关闭。正确理解是 FI…

深入解析

01

目标不同

三次握手解决的是双方能不能通信的问题:客户端发送 SYN,服务端用 SYN 加 ACK 回应,客户端再 ACK 确认,双方的初始序列号、发送能力、接收能力都被确认。连接断开解决的是两个方向的数据流是否都已经结束,TCP 是全双工协议,两个方向要分别关闭。

02

FIN 的含义

TCP 里的 FIN 不是整个连接立刻消失,而是我这一端已经没有数据要继续发送。主动关闭方发出 FIN 后,表示主动方到被动方这个方向不会再发送普通数据,但主动方仍然可以继续接收被动方发来的数据。这就是半关闭,是理解四次挥手的核心。

03

ACK 与 FIN 分离

被动关闭方收到 FIN 后,协议栈需要尽快返回 ACK,确认已经收到对方的关闭请求。这个 ACK 只说明你的 FIN 我收到了。但被动关闭方自己的 FIN 表示我这边也没有数据要发了,这通常要等应用层调用 close 或把剩余数据写完之后才能发生。

04

标准四步

典型过程是:主动关闭方发送 FIN,进入 FIN_WAIT_1;被动关闭方返回 ACK,进入 CLOSE_WAIT,主动关闭方收到 ACK 后进入 FIN_WAIT_2;被动关闭方等应用层结束发送后发送 FIN,进入 LAST_ACK;主动关闭方返回 ACK,进入 TIME_WAIT,被动关闭方收到 ACK 后进入 CLOSED。

05

多出来的一次

多出来的一次不是多余确认,而是被动关闭方单独发送自己的 FIN。连接建立时,服务端的 SYN 和对客户端 SYN 的 ACK 可以自然合并;断开时,被动关闭方收到 FIN 时只能先 ACK,因为它可能还没准备好关闭自己的发送方向。等它真的没有数据要发时,再发送 FIN。

06

报文可合并

如果被动关闭方收到 FIN 时,应用层也已经没有数据要发,或者很快决定关闭,那么 ACK 和 FIN 可能被合并在同一个 TCP 报文里发送。这样抓包时可能看到三个报文完成断开。但这只是报文合并,不改变协议语义:对对方 FIN 的 ACK 和本端自己的 FIN 仍然是两个逻辑动作。

07

TIME_WAIT

主动关闭方最后发送 ACK 后进入 TIME_WAIT,是为了处理两个问题:一是保证最后一个 ACK 如果丢失,被动关闭方重传 FIN 时主动方还能再次 ACK;二是让旧连接中的延迟报文在网络中自然消失,避免影响相同四元组的新连接。

易错点

  • 误以为 FIN 表示整个连接马上关闭。正确理解是 FIN 只关闭本端的发送方向,接收方向仍可能继续工作。
  • 误以为第四次挥手只是多发了一个重复 ACK。实际关键动作是被动关闭方单独发送自己的 FIN。
  • 误以为 ACK 和 FIN 永远不能合并。它们概念上分离,但如果应用层已经准备好关闭,报文层面可以合并发送。
  • 误以为 TIME_WAIT 是被动关闭方的状态。典型情况下,最后发送 ACK 的主动关闭方会进入 TIME_WAIT。
  • 只背四次挥手顺序,不解释全双工和半关闭,会显得停留在记忆层面。

面试官追问

为什么连接建立是三次,不是四次?

建立连接时,服务端收到客户端 SYN 后,既要确认客户端的 SYN,又要发送自己的 SYN。这两个动作可以自然合并成 SYN+ACK,所以不需要四次。

为什么连接建立不能是两次握手?

两次握手无法让服务端确认客户端是否收到了自己的 SYN+ACK。如果旧的延迟 SYN 到达服务端,两次握手还可能让服务端误以为新连接成立。

CLOSE_WAIT 过多说明什么?

CLOSE_WAIT 表示本端已经收到对方 FIN 并回复 ACK,但本端应用还没有关闭自己的发送方向。大量 CLOSE_WAIT 通常说明应用层没有及时 close 连接或释放资源。

为什么主动关闭方要进入 TIME_WAIT?

因为主动关闭方发送的是最后一个 ACK。如果这个 ACK 丢失,被动关闭方会重传 FIN,主动关闭方必须保留状态来重新 ACK,同时等待旧报文自然过期。

FIN_WAIT_2 表示什么?

FIN_WAIT_2 表示主动关闭方的 FIN 已经被对方 ACK,主动方的发送方向已经关闭,但还在等待被动方发送 FIN。此时连接处于半关闭状态。