当一方发送完数据请求关闭连接时,TCP会进行四次挥手,过程如下
TCP A TCP B
1. ESTABLISHED ESTABLISHED
2. FIN-WAIT-1 --> <SEQ=100><CTL=FIN> -->CLOSE-WAIT
3. FIN-WAIT-2 <-- <SEQ=300><ACK=101><CTL=ACK> <-- CLOSE-WAIT
4. TIME-WAIT <-- <SEQ=500><ACK=101><CTL=FIN,ACK> <-- LAST-ACK
5. TIME-WAIT --> <SEQ=101><ACK=501<CTL=ACK> ...
6. TIME-WAIT ... <SEQ=101><ACK=501><CTL=ACK> -->CLOSE
7. TIME-WAIT for 2MSL
8. CLOSE CLOSE
流程图
TCP连接是全双工通信,客户端数据发送完毕了,可能服务端数据还没发送完毕。因此客户端①请求关闭连接后,服务器首先需要②响应一个ACK报文段,避免客户端反复重传请求。但是服务端可能对于客户端请求的数据还没有全部传输完,所以需要等待数据进行传输,服务端的数据传输完之后,③服务器响应一个FIN ACK报文段给客户端,表示服务端已经准备好关闭连接,客户端在接收到这个报文段之后,将响应一个ACK报文段给服务器,服务器收到报文段之后转入CLOSE状态,而客户端将在发送完报文段之后2MSL装入CLOSE状态。
提问:
为什么要四次挥手,不是三次?
发现四次挥手多的那一次是多在了服务端响应了两次ACK报文段,从这个角度去思考,为什么服务端需要响应2次客户端的请求呢?因为TCP是全双工通信,当客户端发送FIN报文段请求关闭连接时,服务端的数据可能还没传输完,所以我们需要等待服务端的数据传输完,假如我们服务器只响应一个ACK报文段的话,要是服务器数据传输这个阶段在其之前进行的话,将导致客户端超时重传FIN报文段,要是服务器数据传输这个阶段在其之后进行的话,那么客户端不知道数据传输结束的标志是什么,所以服务器必须得响应两个ACK报文段。
我们还可以考虑一种情况,省去四次挥手的最后一次挥手,将第三次挥手作为结束的标志,服务端进行第三次挥手之后立马关闭,客户端接收到报文段之后也立马关闭,会怎样?显然,当服务端发送的FIN ACK报文段在网络中丢失时,TCP就会陷入错误,客户端不知道何时转入CLOSE状态,那服务端发送完FIN ACK报文段之后等待一段时间关闭怎么样,这样我们就可以在丢失报文段时对其进行超时重传了?但这个时候又有一个问题,服务端要怎样知道什么时候关闭呢,要是将服务器的LAST-ACK阶段改为时长为1MSL的TIME-WAIT阶段,再去掉客户端的TIMEWAIT阶段是否可行?这种情况服务器无法确定报文段是否送达,故依然客户端的ACK报文段。
PS(图中只在ACK报文段与FIN ACK报文段之间画了个数据传输的字样,但不要以为之间没有报文段的确认与发送)
为什么客户端在发送完最后的ACK报文段之后要等待2MSL才转入CLOSED状态?
首先解释MSL,它就是一个报文段在网络中最长存活时间。假如没有TIME-WAIT这个阶段,会怎样?我们考虑这么一种情况,没有TIME-WATI,客户端发完ACK报文段之后立即关闭,此时假若客户端发送的ACK报文段在网络的传输过程中因某种原因丢失,那么服务端就将不知道什么时候关闭,所以客户端不能立即关闭,需要确保报文段送达,未送达的话服务端就超时重传,客户端收到报文段之后再重发,两个报文段,所以需要等2MSL