真实面经题目 · 原创解析
CLOSE_WAIT 和 TIME_WAIT 分别是什么?
CLOSE_WAIT 和 TIME_WAIT 都是 TCP 连接关闭过程中的状态,但含义完全不同。CLOSE_WAIT 出现在被动关闭方,表示对端已经发来 FIN,本端已经确认,但应用还没有调用 close 结束连接;TIME_WAIT 出现在主动关闭方,表示本端完成主动关闭后仍保留连接一段时间,用于处理延迟报文和保证对端收到最后的 ACK。
真实面经题目 · 原创解析
CLOSE_WAIT 和 TIME_WAIT 都是 TCP 连接关闭过程中的状态,但含义完全不同。CLOSE_WAIT 出现在被动关闭方,表示对端已经发来 FIN,本端已经确认,但应用还没有调用 close 结束连接;TIME_WAIT 出现在主动关闭方,表示本端完成主动关闭后仍保留连接一段时间,用于处理延迟报文和保证对端收到最后的 ACK。
可以先按主动关闭和被动关闭来区分。CLOSE_WAIT 是被动关闭方收到对端 FIN 后进入的状态,内核已经回复 ACK,接下来要等本端应用关闭 socket 并发送自己的 FIN。如果大量 CLOSE_WAIT 长时间存在,通常说明应用层没有正确关闭连接、读写协程卡住、连接池泄漏或异常路径没有释放资源。TIME_WAIT 是主动关闭方发送最后 ACK 后进入的状态,需要等待 2MSL,目的是让网络中的旧报文自然过期,并在对端没有收到最后 ACK 时能够重传 ACK。大量 TIME_WAIT 不一定是 bug,高并发短连接服务很常见,但要结合端口耗尽、连接复用、keep-alive、连接池和内核参数判断。
TCP 是全双工协议,连接关闭不是简单的一次断开,而是两个方向分别关闭。主动关闭方先发送 FIN,表示自己不再发送数据;被动关闭方收到 FIN 后回复 ACK,此时被动方进入 CLOSE_WAIT,仍然可以继续发送剩余数据。随后被动方应用调用 close,发送自己的 FIN;主动关闭方收到后回复最后一个 ACK,并进入 TIME_WAIT。这个流程解释了为什么两个状态分别属于不同的一侧,也解释了它们的排查方向完全不同。
CLOSE_WAIT 表示对端已经关闭发送方向,本端内核已经知道这件事并完成确认,但本端应用还没有真正关闭 socket。它本身不是内核延迟回收,而是在等待用户态程序做收尾动作。正常情况下,CLOSE_WAIT 应该很快过渡到 LAST_ACK;如果大量连接长期停在这里,重点要查应用代码是否在读到 EOF、异常返回、超时、半关闭通知或业务取消时没有执行 close。
TIME_WAIT 表示主动关闭方已经完成四次挥手的最后 ACK,但连接不能立刻删除。原因有两个:第一,最后 ACK 可能丢失,被动关闭方会重发 FIN,主动关闭方需要还能识别并再次 ACK;第二,旧连接的延迟报文可能仍在网络中,等待 2MSL 能降低旧报文污染新连接的概率。它是 TCP 正确性的保护状态,不应一看到数量多就判定为异常。
判断 CLOSE_WAIT 要看持续时间和是否持续增长。如果连接长时间不消失,几乎总是应用层释放问题。判断 TIME_WAIT 要结合流量形态:短连接、大量主动断开、没有连接复用时数量偏高很常见;真正有风险的是本机临时端口耗尽、连接建立失败、文件描述符压力、NAT 设备状态表压力或延迟异常。一个成熟回答要把状态机语义、业务连接模式和系统资源放在一起看。
CLOSE_WAIT 的治理重心在代码路径:确保 finally 或 defer 关闭连接,连接池借还一致,读写超时可退出,异常分支释放资源,并通过 fd、堆栈、协程或线程栈定位卡住的位置。TIME_WAIT 的治理重心在连接模型:优先使用 keep-alive、HTTP/2、多路复用、连接池和服务端主动关闭策略,必要时再评估端口范围、TIME_WAIT 复用、负载均衡和内核参数。不能用调整内核参数掩盖应用层未关闭连接的问题。
因为内核已经收到对端 FIN 并回复 ACK,下一步要等本端应用关闭 socket。如果应用没有 close,内核无法替应用发送 FIN,连接就会停在 CLOSE_WAIT。
2MSL 能覆盖一个报文在网络中往返可能存活的最长时间,让旧连接的延迟报文自然失效,并允许主动关闭方在对端重发 FIN 时再次回复 ACK。
不一定。谁主动关闭连接,谁更容易进入 TIME_WAIT。如果服务端主动断开短连接,服务端就会积累 TIME_WAIT。要看连接复用、主动关闭策略和资源是否真的受影响。
先用连接统计确认本地端口、远端地址和进程,再看进程 fd 数、线程或协程栈、连接池状态和异常日志。重点找读到 EOF 或捕获异常后没有关闭连接的路径。