????????TCP是全双工通信,双方都能作为数据的发送方和接收方,但TCP连接也会有断开的时候。所谓相爱容易分手难,建立连接只有三次,而挥手断开则需要四次,如图1-23所示。A机器想要关闭连接,则待本方数据发送完毕后,传递FIN信号给B机器。B机器应答ACK,告诉A机器可以断开,但是需要等B机器处理完数据,再主动给A机器发送FIN信号。这时,A机器处于半关闭状态(FIN_WAIT_2 ),无法再发送新的数据。B机器做好连接关闭前的准备工作后,发送FIN给A机器,此时B机器也进入半关闭状态(CLOSE_WAIT)。A机器发送针对B机器FIN的ACK后,进入TIME-WAIT状态,经过2MSL ( Maximum Segment Lifetime )后,没有收到B机器传来的报文,则确定B机器已经收到A机器最后发送的ACK指令,此时TCP连接正式释放。具体释放步骤如图所示:
?
?图中的红色字体所示的TIME_WAIT和CLOSE_WAIT分别表示主动关闭和被动关闭产生的阶段性状态,如果在线上服务器大量出现这两种状态,就会加重机器负载,也会影响有效连接的创建,因此需要进行有针对性的调优处理。
TIME_WAIT:主动要求关闭的机器表示收到了对方的FIN报文,并发送出了ACK报文,进入TIME_WAIT状态,等2MSL后即可进入到CLOSED状态。如果FIN_WAIT_1状态下,同时收到带FIN标志和ACK标志的报文时,可以直接进入TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSE_WAIT:被动要求关闭的机器收到对方请求关闭连接的FIN报文,在第一次ACK应答后,马上进入CLOSE_WAIT 状态。这种状态其实表示在等待关闭,并且通知应用程序发送剩余数据,处理现场信息,关闭相关资源。
在TIME_WAIT等待的2MSL是报文在网络上生存的最长时间,超过阈值便将报文丢弃。一般来说,MSL大于TTL衰减至О的时间。在RFC793中规定MSL为2分钟。但是在当前的高速网络中,2分钟的等待时间会造成资源的极大浪费,在高并发服务器上通常会使用更小的值。既然TIME_WAIT貌似是百害而无一利的,为何不直接关闭,进入CLOSED状态呢?原因有如下几点。
在TIME_WAIT等待的2MSL是报文在网络上生存的最长时间,超过阈值便将报文丢弃。一般来说,MSL大于TTL衰减至О的时间。在RFC793中规定MSL为2分钟。但是在当前的高速网络中,2分钟的等待时间会造成资源的极大浪费,在高并发服务器上通常会使用更小的值。既然TIME_WAIT貌似是百害而无一利的,为何不直接关闭,进入CLOSED状态呢?原因有如下几点:
第一,确认被动关闭方能够顺利进入CLOSED状态。如图1-23所示,假如最后一个ACK由于网络原因导致无法到达B机器,处于LAST_ACK的B机器通常“自信”地以为对方没有收到自己的FIN+ACK报文,所以会重发。A机器收到第二次的FIN+ACK报文,会重发一次ACK,并且重新计时。如果A机器收到B机器的FIN+ACK报文后,发送一个ACK给B机器,就“自私”地立马进入CLOSED状态,可能会导致B机器无法确保收到最后的ACK指令,也无法进入CLOSED 状态。这是A机器不负责任的表现。
第二,防止失效请求。这样做是为了防止已失效连接的请求数据包与正常连接的请求数据包混淆而发生异常。
????????因为TIME_WAIT状态无法真正释放句柄资源,在此期间,Socket中使用的本地端口在默认情况下不能再被使用。该限制对于客户端机器来说是无所谓的,但对于高并发服务器来说,会极大地限制有效连接的创建数量,成为性能瓶颈。所以,建议将高并发服务器TIME_WAIT超时时间调小。
|