1. 四次挥手
-
客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
-
服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
-
客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
-
服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
-
客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
-
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
1.1 为什么FIN报文段即使不携带数据,也要消耗一个序号
例如 FIN 包不消耗一个序列号。客户端发送了 100 字节的数据包和 FIN 包,都等待服务端确认。如果这个时候客户端收到了ACK=1000 的确认包,就无法得知到底是 100 字节的确认包还是 FIN 包的确认包。
1.2 为什么要4次挥手
当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
如果服务端确定没有什么数据需要发给客户端,那么当然是可以把 FIN 和 ACK 合并成一个包,四次挥手的过程就成了三次。
1.3 同时关闭
- 当应用层发出关闭命令时,两端均从 E S TA B L I S H E D变为F I N _ WA I T _ 1。
- 这将导致双方各发送一个 F I N,两个F I N经过网络传送后分别到达另一端。
- 收到 F I N后,状态由F I N _ WA I T _ 1变迁到C L O S I N G,并发送最后的 A C K。当收到最后的 A C K时,状态变化为T I M E _ WA I T。