真实面经题目 · 原创解析
TCP 四次挥手的流程是什么?
TCP 四次挥手本质上是连接两端分别关闭各自发送方向的过程。由于 TCP 是全双工协议,一端发出 FIN 只表示自己不再发送数据,但仍能接收对端数据;对端确认后,也可能还要继续发送剩余数据,等发送完成再发自己的 FIN。因此面试回答要讲清 FIN 和 ACK 的含义、半关闭边界、双方状态迁移,以及 TIME_WAIT、CLOSE_WAIT、FIN_WAIT、LAST_ACK 等状态背后的工程意义。
真实面经题目 · 原创解析
TCP 四次挥手本质上是连接两端分别关闭各自发送方向的过程。由于 TCP 是全双工协议,一端发出 FIN 只表示自己不再发送数据,但仍能接收对端数据;对端确认后,也可能还要继续发送剩余数据,等发送完成再发自己的 FIN。因此面试回答要讲清 FIN 和 ACK 的含义、半关闭边界、双方状态迁移,以及 TIME_WAIT、CLOSE_WAIT、FIN_WAIT、LAST_ACK 等状态背后的工程意义。
TCP 四次挥手通常从主动关闭方调用关闭开始。第一步,主动关闭方发送 FIN,表示自己的发送方向已经结束,进入 FIN_WAIT_1;第二步,被动关闭方收到 FIN 后回复 ACK,表示确认对方不会再发数据,被动方进入 CLOSE_WAIT,主动方收到 ACK 后进入 FIN_WAIT_2。此时连接处于半关闭状态:主动方不能再发送普通业务数据,但仍可以接收被动方尚未发完的数据。第三步,被动关闭方在应用层也完成发送并关闭后,发送自己的 FIN,进入 LAST_ACK;第四步,主动关闭方收到该 FIN 后回复 ACK,进入 TIME_WAIT,等待一段时间后进入 CLOSED;被动方收到最后的 ACK 后进入 CLOSED。通常是四次而不是三次,是因为被动方对主动方 FIN 的确认 ACK,和被动方自己关闭发送方向的 FIN,在语义上不是同一件事,只有当被动方刚好也没有数据要发时才可能被合并。
TCP 连接不是一根只能整体开关的管道,而是两个方向独立的数据流:客户端到服务端一个方向,服务端到客户端另一个方向。FIN 的含义是“我这一侧以后不再发送数据”,不是“整个连接立刻失效”。因此一端发 FIN 后,对端仍然可以继续发送已经准备好或正在处理中的数据,这就是四次挥手必须从双向关闭角度理解的原因。
主动关闭方先发送 FIN,并进入 FIN_WAIT_1,表示自己的发送方向进入关闭流程。被动关闭方收到 FIN 后,内核会回 ACK,表示已经确认这个方向的结束,然后被动方进入 CLOSE_WAIT。主动方收到这个 ACK 后进入 FIN_WAIT_2。到这里,只关闭了主动方到被动方的发送方向,被动方到主动方的方向仍然可能继续传输数据。
半关闭状态下,主动关闭方已经发出 FIN,原则上不能再发送普通业务数据,因为 FIN 在字节流中代表本方向数据结束;但它仍然可以接收被动关闭方发来的数据,并正常确认这些数据。被动关闭方则处于 CLOSE_WAIT,它知道对方不再发送,但自己是否还能发送,取决于本地应用是否还有响应、日志、尾包或缓冲区数据需要发完。
被动关闭方只有在应用层也决定关闭发送方向时,才会发送自己的 FIN,并进入 LAST_ACK。主动关闭方收到该 FIN 后,需要回最后一个 ACK,然后进入 TIME_WAIT。被动方收到这个 ACK 后就可以进入 CLOSED。主动方不能立即消失,因为最后这个 ACK 可能丢失,如果丢失,被动方会重传 FIN,主动方必须还能识别并再次确认。
三次握手能建立连接,是因为建立时双方的同步和确认可以被组织在较少报文中;关闭时不同,因为关闭两个发送方向往往不是同时发生。被动方收到 FIN 后只能先确认“我知道你不发了”,但不能立刻保证“我也不发了”。只有等应用把剩余数据处理完,才会发自己的 FIN,所以 ACK 和 FIN 通常分开发送,表现为四次。
TIME_WAIT 主要有两个作用。第一,确保最后一个 ACK 丢失时,主动关闭方还能收到被动方重传的 FIN 并重新确认,避免被动方长时间卡在 LAST_ACK。第二,让网络中属于旧连接的迟到报文自然过期,避免相同四元组的新连接被旧报文干扰。它是 TCP 正确性的一部分,不只是一个可以随便删除的等待状态。
CLOSE_WAIT 多通常说明本机作为被动关闭方收到了对端 FIN,但本地应用没有及时关闭 socket,常见原因是业务线程阻塞、连接对象未释放、读到 EOF 后没有 close,或连接池管理不当。FIN_WAIT_2 多则常见于主动关闭方已经收到 ACK,却迟迟等不到对端 FIN,可能是对端应用还在发送、未关闭,或者协议层关闭流程设计不清晰。
因为被动关闭方收到 FIN 后,只能立刻确认对方的发送方向结束,但自己可能还有数据没有发完。ACK 是确认对方关闭,FIN 是声明自己关闭,两个动作的触发时机不同。只有在被动方恰好也准备关闭时,ACK 和 FIN 才可能合并。
主动关闭方收到对端 FIN 后会发送最后一个 ACK,因此它需要保留连接状态一段时间。如果这个 ACK 丢失,对端会重传 FIN,主动关闭方必须能再次回复 ACK。同时等待也能让旧连接的迟到报文在网络中失效。
CLOSE_WAIT 很多通常说明本机收到了对端 FIN,并且内核已经回复 ACK,但本地应用没有继续调用 close 结束自己的发送方向。常见原因包括读到 EOF 后未释放连接、线程阻塞、异常路径漏关 socket 或连接池生命周期管理错误。
FIN_WAIT_2 表示主动关闭方的 FIN 已被确认,但还没有收到对端 FIN。它可能说明对端应用仍有数据要发送,也可能说明对端没有正确关闭连接。如果数量异常,需要结合对端 CLOSE_WAIT、应用日志和超时配置一起分析。
能,但只能是未关闭发送方向的一端继续发送。收到 FIN 代表对方不会再发送数据,不代表本端必须立刻停止发送。本端仍可把剩余数据发送完,再发送自己的 FIN;但已经发出 FIN 的一端不能再发送普通业务数据。