1.四次挥手服务端和客户端的状态:
- 主动关闭连接的一方,调用 close ();协议层发送 FIN 包;
- 被动关闭的一方收到 FIN 包后,协议层回复 ACK;然后被动关闭的一方,进入 CLOSE_WAIT 状态,主动关闭的一方等待对方关闭,则进入 FIN_WAIT_2 状态;此时,主动关闭的一方等待被动关闭一方的应用程序,调用 close 操作;
- 被动关闭的一方在完成所有数据发送后,调用 close () 操作;此时,协议层发送 FIN 包给主动关闭的一方,等待对方的 ACK,被动关闭的一方进入 LAST_ACK 状态;
- 主动关闭的一方收到 FIN 包,协议层回复 ACK;此时,主动关闭连接的一方,进入 TIME_WAIT 状态;而被动关闭的一方,进入 CLOSED 状态;
- 等待 2MSL 时间,主动关闭的一方,结束 TIME_WAIT,进入 CLOSED 状态;
2.总结上面的过程,得出一次 socket 关闭操作:
- 主动关闭连接的一方 – 也就是主动调用 socket 的 close 操作的一方,最终会进入 TIME_WAIT 状态;
- 被动关闭连接的一方,有一个中间状态,即 CLOSE_WAIT,因为协议层在等待上层的应用程序,主动调用 close 操作后才主动关闭这条连接;
- TIME_WAIT 会默认等待 2MSL(2 倍的max segment lifetime) 时间后,才最终进入 CLOSED 状态;
- 在一个连接没有进入 CLOSED 状态之前,这个连接是不能被重用的!
3.TIME_WAIT 并不可怕,CLOSE_WAIT 才可怕,因为 CLOSE_WAIT 很多,表示说:
- 要么是你的应用程序写的有问题,没有合适的关闭 socket;
- 要么是说,你的服务器 CPU 处理不过来(CPU 太忙)或者你的应用程序一直睡眠到其它地方 (锁,或者文件 I/O 等等),你的应用程序获得不到合适的调度时间,造成你的程序没法真正的执行 close 操作。
4.TIME_WAIT 有什么用?
- 防止前一个连接上延迟的数据包或者丢失重传的数据包,被后面复用的连接错误的接收
- 确保连接方能在时间范围内,关闭自己的连接
5.为什么 TIME_WAIT 状态 停留 2MSL(max segment lifetime)时间?
-
为了防止上次连接的报文数据影响到下次的连接,有充分的的时间处理上次连接的报文信息。
-
客户端最后发的 ACK 可能会丢失,此时服务器端会重新发送 FIN,若此时客户端处于 closed,会响应 rst (rst 段标识复位,用来异常的关闭连接) 而不是 ACK。因此客户端是 TIME_WAIT 状态,不是 closed。
6.什么原因造成出现大量CLOSE_WAIT?
- 出现大量 close_wait 的现象主要原因是某种情况下对方关闭了 socket 链接,但是我方忙与读或者写,没有关闭连接。
7.什么原因造成大量 TIME_WAIT
- 在高并发短连接的 TCP 服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量 socket 处于 TIME_WAIT 状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
8.如何处理大量CLOSE_WAIT?
- 给每一个 socket 设置一个时间戳 last_update,每接收或者是发送成功数据,就用当前时间更新这个时间戳。定期检查所有的时间戳,如果时间戳与当前时间差值超过一定的阈值,就关闭这个 socket。
- 使用一个 Heart-Beat 线程,定期向 socket 发送指定格式的心跳数据包,如果接收到对方的 RST 报文,说明对方已经关闭了 socket,那么我们也关闭这个 socket。
【Java 面试那点事】
这里致力于分享 Java 面试路上的各种知识,无论是技术还是经验,你需要的这里都有!
这里可以让你【快速了解 Java 相关知识】,并且【短时间在面试方面有跨越式提升】
面试路上,你不孤单!