TCP三次握手期间异常
第一次握手丢失,会发生什么?
当客户端想和服务端建立TCP连接的时候,首先第一个发的就是SYN报文,然后进入SYN_SENT状态。
在这之后,如果客户端迟迟收不到服务端的SYN+ACK报文(第二次握手),那就触发超时重传机制。不同版本的操作系统超时时间不同,有的1s,有的3s,这个时间是写死在内核中的,几乎不会有人去改。
当客户端在1s后没收到服务端的SYN+ACK报文的话,客户端就会重发SYN报文,重试的次数也是有内核中参数控制,一般是5,通常第一次重传是在1s后,第二次是在2s后,第三次是在4s后,以此类推。当第五次重传后,会继续等待32s,如果服务端仍然没响应,则断开TCP连接,所以总耗时为1+2+4+8+16=32=63s。
第二次握手丢失,会发生什么
当服务器收到客户端的第一次握手后,就会回复SYN+ACK报文给客户端,这就是第二次握手,此时服务端进入SYN_REVD状态。
第二次握手的SYN-ACK报文其实有两个目的 1.ack是对第一次握手的确认报文 2.syn是服务端发起建立连接的tcp报文
所以如果第二次握手丢失了,客户端迟迟没有收到第二次握手的确认报文,所以服务端以为自己的第一次握手的syn报文丢失了,于是客户端会触发上述讲的超时重传机制,重传第一次握手的syn报文。
因为第二次握手中包含服务端的SYN报文,所以当客户端收到后需要给服务端发送ACK报文(第三次握手),服务端才认为该SYN报文被客户端收到了,那么如果第二次握手丢失了,服务端就收到不到第三次握手的ack报文,于是服务端也会触发超时重传机制,重传SYN-ACK报文。
第三次握手丢失,会发生什么
客户端收到服务器的SYN-ACK报文后,就会给服务器发送一个ACK报文,也就是第三次握手,此时客户端进入ESTABLISH状态。
因为第三次握手是对第二次握手的确认报文,所以当第三次握手丢失后,也就是服务端迟迟收不到确认报文,那么会触发服务端的超时重传,即重传SYN-ACK报文,知道第三次握手成功或者达到最大重传次数断开连接。
注意:ACK报文是不会重传的,当ACK报文丢失,则由对方重传SYN报文
TCP四次挥手期间的异常
第一次挥手丢失,会发生什么
当客户端调用close函数后,就会想服务端发送FIN报文,试图与服务器断开连接,此时客户端进入FIN_WAIT_1状态。
正常情况,如果能及时收到服务端的ack,那客户端很快就会进入FIN_WAIT_2状态。
如果第一次挥手丢失了,那客户端迟迟收不到服务端的ack报文,也会触发超时重传机制,重传FIN报文,当重传次数达到一定次数的时候,就不在发送FIN报文,直接进入close状态
第二次挥手丢失,会发生什么
当服务器收到客户端的第一次挥手后,就会发送给服务端一个ACK报文,此时服务端进入CLOSE_WAIT状态,前面我们也强调过,ACK报文是不会重传的,所以会触发客户端的超时重传机制。
当客户端收到第二次挥手,也就是收到服务端ack报文后,客户端会进入FIN_WAIT_2状态,对于最开始的close函数关闭的连接,由于无法再发送和接受数据,所以FIN_WAIT_2状态不会持续太久,默认是60s,这就意味着在调用close函数后,在60s后还没收到第三次握手FIN报文,连接也会直接关闭。
第三次挥手丢失,会发生什么
当服务器收到客户端的FIN报文后,内核会自动恢复ACK,同时连接处于CLOSE_WAIT状态,但是内核是没有权限替现成关闭连接,必须由线程主动调用close函数来触发服务端发送的FIN报文,也就是第三次挥手。
服务端处于CLOSE_WAIT状态时,调用close函数,内核就会发出FIN报文,同时连接进入LAST_ACK状态,等待客户端返回ack报文来确认关闭连接。如果迟迟收不到这个ack,服务端就会重发FIN报文。
第四次挥手丢失,会发生什么
当客户端收到服务端的第三次挥手的FIN报文后,就会返回ack报文,此时客户端进入TIME_WAIT状态,在Linux系统中,TIME_WAIT状态会持续60s后才会进入关闭状态。
由于第四次挥手丢失,服务端迟迟收不到ack,所以也就触发服务端的超时重传机制重传FIN报文。
整理自链接:https://blog.csdn.net/qq_34827674/article/details/119809480
|