TCP断开连接为什么是四次挥手?三次行不行?
前言
四次挥手相信大家都很熟悉了,为什么相较于TCP建立连接的三次握手需要多一次的原因网上也可以搜索到很多,本篇想要讲的主体和网上有点不一样,三次挥手在特定情况下也是可以的,相信大家搜到的原因说的都是特定情况下第二次和第三次挥手可以合并,那大家是否想过如果三次挥手是去掉第四次挥手呢?可以挥手成功吗?
一、首先,还是先讲一讲四次挥手的流程
-
第一次挥手:客户端发起断开连接请求,也就是发送一个
FIN(finish)
报文,并且报文中会指定一个序列号(序列号作用就是防止由于报文延迟到达而导致客户端已经超时重传了而出现服务端先后收到两次FIN
报文,所以应该使用序列号唯一标记每一次发送的FIN
报文,防止历史报文又被接收)。发送完成后客户端进入FIN_WAIT1
状态,不再发送数据,等待来自服务端的确认 -
第二次挥手:服务端收到
FIN
报文后,就会把客户端的序列号值+1作为ACK报文的序列号,将确认收到ACK
报文以及自身的随机序列号发送给客户端,发送完毕后服务端处于CLOSE_WAIT
状态(服务端在收到客户端断开连接FIN报文后,并不会立即关闭连接) -
第三次挥手:服务端数据全部传输完毕,服务端也申请断开连接,和客户端的第一次挥手一样,发送
FIN
报文,且指定一个序列号,发送完毕服务端进入LAST_ACK
状态 -
第四次挥手:客户端收到
FIN
报文后,同样把服务端的序列号+1作为确认收到ACK
报文的序列号值并发送,此时客户端进入TIME_WAIT
状态(注意还没有进入关闭CLOSED
状态,因为客户端发送的ACK
报文可能在传输过程中丢失,所以需要等到服务端也确认收到才进入关闭状态,具体客户端等待时间大概需要略大于超时重传时间,超时重传时间过后没有收到服务端新的FIN
报文就说明ACK
报文被服务端接收到了),过了这段时间后客户端就可以进入CLOSED
关闭状态,而服务端在接收到ACK
报文之后也关闭连接,进入CLOSED
状态。TCP连接成功断开!
二、为什么TCP断开连接不是像建立连接一样的三次握手?而是需要四次?
原因在于客户端请求断开连接后,但是服务端可能还存在没有传输完的数据,如果此时服务端就直接断开连接那势必会造成数据的丢失,TCP也就不可靠了。所以服务端需要等待所有数据发送完毕再请求断开,也就是服务端的ACK
和FIN
报文是分两次发送的。而TCP建立连接是不需要这个等待过程的,所以三次握手把服务端确认收到ACK
报文和请求连接报文合并到了一起。
三、四次挥手可以变成三次吗?
既然上面提到之所以断开连接是挥手四次,是因为服务端在客户端请求断开连接后自身数据可能还没有发送完毕,如果此时断开连接就会造成数据丢失而变得不可靠。那如果发送完毕了呢?所以四次挥手是可以变成三次挥手的,条件就是服务端在收到客户端的请求断开连接FIN
报文的时候已经不需要再发送数据了,那第二次挥手和第三次挥手就可以合并,从而实现三次挥手
以上其实网上可以找到很多相似的解释,笔者也在此指出。除此之外,笔者还有一点小思考。接下来才是我想写这篇文章的主要原因。
四、四次挥手想变成三次挥手可以是去掉第四次挥手吗?
三次挥手有两种情况:一种就是上面的把第二次挥手和第三次挥手合并为一次,另一种笔者想到的是去掉第四次挥手是否可行?这个问题的答案网上应该不多见,所以我试着来讲一下
去掉第四次挥手会造成什么呢?
第四次挥手是客户端发送响应服务端FIN
报文的ACK
报文,所以如果服务端不用确保收到ACK
报文之后才关闭连接,那么就是服务端不知道客户端是否已经成功关闭连接了,服务端就先一步关闭了连接。设想这样一种情况,第三次挥手中服务端发送的FIN
报文丢失了,由于我们设想的取消了第四次挥手的三次挥手
的成立性,也就是服务端此时已经关闭了连接,而客户端(此时客户端是半关闭状态)由于收不到来自服务端的FIN
报文,那又需要重新发送FIN
报文请求断开连接,可此时服务端已经关闭连接了啊,那也就是说,服务端要想收到客户端的FIN
报文,还需要重新三次握手建立连接之后才能接收到这个FIN
报文,岂不是大大的资源浪费,建立TCP三次握手连接居然是为了断开连接?!!
这也就是第四次挥手存在的必然性。
所以,四次挥手的设计的是很合理的,每一步都存在着特定的意义和作用