TCP断开连接的相关问题
1.TCP四次挥手过程和状态变迁
TCP断开连接时通过四次挥手方式,双方都可以主动断开连接,断开连接后主机中的资源将被释放。
(1)客户端打算关闭连接,此时会发送一个TCP首部FIN标志位被置为1的报文,即FIN报文,之后客户端进入FIN_WAIT_1状态。
(2)服务端收到该报文后,就向客户端发送ACK应答报文,接着服务端进入CLOSED_WAIT状态。
(3)客户端收到服务端的ACK应答报文后,之后进入FIN_WAIT_2状态。
(4)等待服务端处理完数据后,也向客户端发送FIN报文,之后服务端进入LAST_ACK状态。
(5)客户端收到服务端的FIN报文后,回一个ACK应答报文,之后进入TIME_WAIT状态。
(6)服务端收到了ACK应答报文后,就进入CLOSE状态,至此服务端已经完成连接的关闭。
(7)客户端在经过2MSL时间后,自动进入CLOSE状态,至此客户端也完成连接的关闭。
每个方向都需要一个FIN和一个ACK,因此通常被称为四次挥手。
这里值得注意的是:主动关闭连接的,才有TIME_WAIT状态。
2.为什么挥手需要四次?
关闭连接时,客户端向服务端发送FIN报文时,仅仅表示客户端不再发送数据了但是还能够接收数据;
服务器收到客户端的FIN报文时,先回一个ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN报文给客户端表示同意现在关闭连接。
所以说,服务端通常需要等待完成数据的发送和处理,所以服务端的ACK和FIN一般都会分开发送,从而比三次握手多了一次。
3.为什么TIME_WAIT等待的时间是2MSL?
MSL是报文的最大生存时间(Maximum Segment Lifetime),它是任何报文在网络上存在的最长时间,超过这个时间报文就会被丢弃。因为TCP报文基于IP协议的,而IP头中有一个TTL字段,是IP数据报可以经过的最大路由数,每经过一个处理它的路由器,此值就减1,当这个值为0时,就表示数据报将被丢弃,同时发送ICMP报文通知源主机。MSL和TTL的区别是:MSL的单位是时间,而TTL是经过路由跳数,所以MSL应该要大于等于TTL消耗为0的时间,以确保报文已被自然消亡。
TIME_WAIT等待2倍的MSL:网络中可能存在来自发送方的数据包,当这些数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待2倍的时间。
比如,如果被动关闭方没有收到断开连接的最后的ACK报文,就会触发超时重发FIN报文,另一方接收到FIN后,会重发ACK给被动关闭方,一来一去正好是2个MSL。这个时间是从客户端收到FIN后发送ACK开始计时的,如果在TIME_WAIT时间内,应为客户端的ACK没有传输到服务端,客户端又收到了服务端重发的FIN报文,那么2MSL时间将重新计时。
4.为什么需要TIME_WAIT状态?
主动关闭连接的一方才会有TIME_WAIT状态。
(1)原因一:防止旧连接的数据包
如果TIME_WAIT没有等待时间或者时间过短,被延迟的数据包抵达会发生什么?
服务端在关闭连接之前发送SEQ=301报文,被网络延迟,这时有相同端口的TCP连接被复用后,被延迟的SEQ=301抵达了客户端,那么客户端有可能正常接收这个过期的报文,这就会产生数据错乱等严重的问题。所以,TCP中有2MSL这个时间,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是在新建立连接所产生的。
(2)保证连接正确关闭
等待足够的时间以确保最后的ACK能让被动关闭方接收,从而帮助其正常关闭。
如果客户端四次挥手的最后一个ACK报文在网络中被丢失,此时如果客户端TIME_WAIT过短或没有,就直接进入了CLOSE状态,那么服务端就会一直处于LAST_ACK状态。当客户端发起建立连接的SYN请求报文后,服务端会发送RST报文给客户端,连接建立的过程就会被中止。
而如果TIME_WAIT等待时间足够长的话:(1)服务端正常接收到四次挥手的最后一个ACK报文,则服务端正常关闭连接。(2)服务端没有收到四次挥手的最后一个ACK报文,重发FIN关闭连接报文等待新的ACK报文。
所以,客户端在TIME_WAIT状态等待2MSL时间后,就可以保证双方的连接都可以正常关闭。
5.TIME_WAIT过多有什么危害?
如果服务器有处于TIME_WAIT状态的TCP,则说明是由服务器方主动发起的断开请求。过多的TIME_WAIT状态的危害有:
- 对内存资源的占用;
- 对端口资源的占用,一个TCP连接至少消耗一个本地端口,如果TIME_WAIT状态过多,占满了所有的端口资源,则会导致无法建立新的连接。
6.如果已经建立了连接,但是客户端突然出现了故障了怎么办?
TCP中有一个保活机制,这个机制的原理是:
定义一个时间段,在这个时间段,如果没有任何连接相关的活动,TCP保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的TCP连接已经死亡,系统内核将错误信息通知给上层应用程序。
如果开启了TCP保活,需要考虑这三种情况:
- 对端程序是正常工作的,当TCP保活的探测报文发送给对端,对端会正常响应,这样TCP保活时间会被重置,等待下一个TCP保活时间的到来;
- 对端程序崩溃并重启,当TCP保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个RST报文,这样很快就会发现TCP连接已经被重置;
- 对端程序崩溃或对端由于其他原因导致报文不可达,当TCP保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP汇报该TCP连接已经死亡。