怎样强制断开TCP连接

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了怎样强制断开TCP连接相关的知识,希望对你有一定的参考价值。

TCP通信的话,服务端断开时会自动通知客户端客户端处理该事件就可以了 参考技术A 数据传输结束后,通信的双方都可释放连接。现在A和B都处于ESTABLISHED状态。A的应用程序先向TCP发出连接释放报文段,主动关闭TCP连接。A把连接释放报文段的首部FIN置为1,序号seq=u,它等于前面已传送过的数据的最后一个字节的序号加1。这时A进入FIN-WAIT-1状态,等待B的确认。

B收到连接释放报文段后即发出确认,确认号是ack=u+1,而这个报文段自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号加1。然后B就进入CLOSE-WAIT状态。TCP服务器进程这时通知高层应用进程,因为从A到B这个方向的连接释放了,这时的TCP连接处于半关闭状态,即A已经没有数据要发送了,但B若发送数据,A仍要接受。也就是说,从B到A这个方向的连接并未关闭。这个状态可以会持续一些时间。

A收到B的确认后,就进入FIN-WAIT-2状态,等待B发出的连接释放报文段。

若B已经没有要向A发送的数据,其应用进程就通知TCP释放连接。这时B发出的连接释放报文段必须使用FIN=1。现假定B的序号为w(在半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。这是B就进入LAST-ACK状态,等待A的确认。

在A收到B的连接释放报文段后,必须对此发出确认。在确认报文段中把ACK置为1,确认号ack=w+1,而自己的序号是seq=u+1(前面的FIN报文消耗了1个序号)。然后进入TIME-WAIT状态。请注意,现在TCP连接还没释放掉。必须再经过2MSL后,A才进入到CLOSED状态。MSL叫最长报文段寿命,一般为2分钟。

当B收到A发出的确认,就进入CLOSED状态。由此可见B结束TCP连接的时间要比A早一些。等到2MSL结束后A也进入CLOSED状态,至此完成了TCP四次挥手断开连接全过程。

tcp连接的断开

参考技术A TCP的断开就是经过四次挥手:

这是正常的情况,客户端主动tcp连接断开的过程。客户端先是发送一个FIN为一的报文,然后进入FIN_WAIT_1的状态。
服务器收到FIN报文后,发送一个ACK报文,然后进入CLOSED_WAIT状态。
客户端收到服务器的ACK报文进入FIN_WAIT_2状态。
等到服务器觉得他数据处理好了,可以关闭的时候,会发送一个FIN报文,然后进入LAST_ACK。等待最后一个应答。
让客户端收到服务器FIN报文,就进入TIME_WAIT状态了,随后发送最后一个ACK报文,然后close。
客户端再等待2msl后也自己主动关闭。而只有主动关闭的情况下,才会有TIME_WAIT。

那么为什么四次挥手需要四次呢?
三次握手其实就是在第二次把ACK和SYN两个报文合并成一个发,但是断开的过程可能还有一方需要处理下数据,需要延长点时间,等处理好再发FIN,所以就比三次握手多了一次。

这里还有一个问题,为什么需要TIME_WAIT,然后到close需要2msl的时间呢?

先说下什么是MSL,也就是报文的最长生存时间,超过这个时间的报文就要被丢弃掉。tcp是基于ip的,ip上有个生存时间TTL,是ip报文可以经过的最大路由数量,每经过一个路由就减1,减到0,ip报文就丢弃掉,然后通过ICMP通知源主机,我们的ping也算是经过这个。当然msl和ttl还是有区别的,msl是时间,ttl是路由数量,msl也是大于等于ttl的。在linux中,2msl默认是60秒。

前文也说了,只有主动发起断开连接的进程才会有time wait状态。time wait+2msl有两个原因:
1.防止旧连接的数据包

像这个seq 301的包,如果因为网络的原因被延迟了,而没有time wait或者很短,那么连接断开后,又建立新的连接,这个时候这个包到了,可能就导致数据紊乱了。而2msl可以保证两个方向的包在断开前丢弃掉。

2.保证正确的断开连接
2msl的时间也是保证第四个报文的ack可以被被动关闭方接收到。

如图,假设time wait比较短或者没有,当最后的ack报文丢失的时候。客户端已经close了,而服务器一直处于last ack的状态。这样连接就不能正常断开了。而如果有time wait +2msl这个情况就可以避免。假设服务器没有收到最后一个ack报文,服务器会重发FIN等待客户端的ack。
这样就可以保证不会出现一端断开,另外一端没有断开的情况了。

有时候我们在服务器上会看到很多time wait。time wait一般就是服务器主动发起的断开请求才会产生的状态。所以time wait过多,第一个是系统资源会大量消耗,还有是端口如果占的太多,会导致没办法创建新连接。这个时候可以把linux的net.ipv4.tcp_tw_reuse开启,置为1,可以复用time wait超过1秒的连接。

这边再说说tcp的保活机制。也就是怎么长期维持客户端和服务端的连接。
在一个时间段内,如果没有连接等相关活动,tcp的保活机制会定期发探测报文,如果连续几个探测报文就没有回应,就将错误信息报告给系统,系统通知上层应用。

在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔,以下都为
默认值:
tcp_keepalive_time=7200:表示保活时间是 7200 秒(2⼩时),也就 2 小时内如果没有任何连接
相关的活动,则会启动保活机制
tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;
tcp_keepalive_probes=9:表示检测 9 次无响应,认为对⽅方是不不可达的,从⽽而中断本次的连接。
也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。
当然这个时间也可以自己配置。

以上是关于怎样强制断开TCP连接的主要内容,如果未能解决你的问题,请参考以下文章

都说 TCP 是面向连接的,怎样才算是一个连接呢?

STM32F107+LWIP怎样判断网络已经连接成功或断开的

这就是TCP?

swoole tcp突然断开连接

tcp连接的断开

TCP的连接与断开