1。前言说起TCP协议,谈的最多的就是三次握手和四次挥手,但是你有没有想过如果三次握手或者四次握手出现异常怎么处理-方式波?谁来处理?TCP作为一种可靠的协议,在传输数据前后都需要在两端建立连接,并在两端维护连接的状态。TCP并没有那么神奇。面对不断变化的网络状况,只能通过不断的重传和各种算法来保证可靠性。当数据传输完成,需要断开连接时,TCP会通过四次握手完成双端断开,回收各自的资源。那么今天就继续说说在TCP的四路浪潮中,如何处理异常、单端运行等问题。2.TCP四向波2.1四向波的简单认识虽然我们说的是四向波的异常情况,但是在此之前,我们先简单了解一下TCP的四向波。当数据传输完成需要断开连接时,TCP会挥手四次安全断开。为什么握手要三次,而挥手要四次?本质上,两端都需要经过一个“分手”的过程来保证自己和对端的状态是正确的。本着友好协商的态度,如果自己先分手,也要给对方最大的善意,不能让对方措手不及。你说不想玩,那你就不玩了,以后谁还敢跟你玩。下图是经典的TCP四波报文和双端状态的变化。解释一下这张图:1、一开始,两端都还处于ESTABLISHED状态,正在传输数据,一端可以发起一个“FIN”包,准备断开连接。在这个场景中,客户端发起一个“FIN”请求。发出“FIN”后,客户端进入FIN-WAIT-1状态。2、服务器收到“FIN”报文后,回复“ACK”表示知道,并从ESTABLISHED状态进入CLOSED-WAIT状态,开始做断开连接前的一些准备工作。3、客户端收到前一个“FIN”的回复“ACK”报文后,进入FIN-WAIT-2状态。并且当服务端准备断开连接时,也会向客户端发送“FIN,ACK”消息,表示我没问题,请求断开连接,发送消息后,服务端进入LAST-ACK状态。4、客户端收到“FIN,ACK”报文后,会立即回复“ACK”表示知道,进入TIME_WAIT状态。出于稳定性和安全性的考虑,客户端会在TIME-WAIT状态等待2MSL,最后进入CLOSED状态。5、服务端收到客户端的“ACK”报文后,直接从LAST-ACK状态进入CLOSED状态。正常挥手四次后,两端进入CLOSED状态,之后,两端正式断开。2.2TCPwaving的异常我们简单了解一下四次waving的正常发包和响应过程。接下来我们继续看四次挥手过程中出现的异常情况。我们已经讲过三次握手的正常发包和响应,以及两端的状态反转。接下来我们看一下三次握手过程中出现的异常情况。1.断开连接的FIN包丢失。之前我们一直强调,如果发送一个数据包,只要在一定时间内没有收到对端的“ACK”回复,就认为该数据包丢失,并触发超时重传机制。它不关心是自己发的包丢了还是对方的“ACK”丢了。所以这里,如果客户端先发送的“FIN”包丢失,或者没有收到对端的“ACK”回复,就会触发超时重传,直到达到重传次数,才会连接成功直接关闭。对于服务端来说,如果没有收到客户端发送的“FIN”,是没有感知的。一段时间后,连接也关闭了。2、服务端第一次发送的ACK丢失。此时,由于客户端没有收到“ACK”响应,会尝试重传之前的“FIN”请求,服务器收到后会重传“ACK”。此时服务器已经进入CLOSED-WAIT状态,开始准备断开连接。当它就绪时,它会回复“FIN,ACK”。注意,这条消息携带了前一个“ACK”的响应序号。只要消息不丢失,client可以直接从FIN-WAIT-1状态进入TIME-WAIT状态,带有“FIN,ACK”包中的响应序号,开始等待最多2MSL。3、服务端发送的FIN和ACK丢失。服务器将在超时后重新传输。此时client有两种情况,要么处于FIN-WAIT-2状态(之前的ACK也丢失),将永远等待;或者处于TIME-WAIT状态,会等待2MSL时间。也就是说,client会存在一小段时间,在收到server发来的“FIN,ACK”包后,client也会回复一个“ACK”响应,做自己的状态切换。4、客户端最后回复的ACK丢失。客户端回复“ACK”后,会进入TIME-WAIT状态,开始等待最多2MSL。服务器会因为没有收到“ACK”回复而重试一段时间,直到服务器重试超时,主动断开连接。或者等待新客户端连接后,收到服务器的“FIN”报文重试后,回复“RST”报文,收到“RST”报文后重置服务器状态。5、client收到ACK后,server跑路。客户端收到“ACK”后,进入FIN-WAIT-2状态,等待服务器发来的“FIN”包,如果服务器跑路了,这个包就永远等不到了。在TCP协议中,没有对这种状态的处理机制。但不管协议如何,系统都会处理,操作系统会接管这个状态。比如在Linux下,可以通过tcp_fin_timeout参数为这个状态设置一个超时时间。需要注意的是,当超过tcp_fin_timeout的限制时,状态不会切换到TIME_WAIT,而是直接进入CLOSED状态。参考:https://blog.huoding.com/2016/09/05/5426。客户端收到ACK后,客户端自己跑路。客户端收到“ACK”后直接跑路,后续服务端发送的“FIN,ACK”没有接收者,不会得到回复,继续使用TCP超时重试机制。此时服务端处于LAST-ACK状态。那么需要分两种情况来分析:一定时间后,服务器主动断开连接。收到“RST”后,主动断开连接。“RST”消息是复位消息,表示当前错误已经发生,应该回到初始状态。如果客户端跑掉后有新的客户端接入,就会在这里发送“SYN”期望建立连接。此时会忽略“SYN”,直接回复“FIN,ACK”报文。收到“FIN”报文后,不会识别,会回复“RST”报文。参考:https://vincent.bernat.ch/en/blog/2014-tcp-time-wait-state-linux3.总结时刻今天我们讲了TCP在四波阶段出现错误时的一些处理策略。大多数情况下,TCP协议本身是有可靠性保证的,比如超时重传,有时,操作系统需要接管一些状态,比如tcp_fin_timeout等。关于TCP三次握手的异常情况,在上一篇文章中有说明,有需要的可以点击蓝字阅读。【本文为专栏作家“张扬”原创稿件,转载请微信♂联系作者获得授权】点此查看作者更多好文
