TCP通过3次握手建立连接,4次挥手关闭连接。完成一次TCP连接的生命周期
三次握手
1.第一次握手:A的TCP客户进程向B发出连接请求报文段(首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号),此时TCP客户进程进入SYN-SENT(同步已发送)状态。
2.第二次握手:B收到连接请求报文段后,如同意建立连接,则向A发送确认报文(SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y),B进程进入SYN-RCVD(同步收到)状态,A进入ESTABLISHED(已建立连接)。
3.第三次握手:A收到B的确认后,要向B发送确认收到确认的报文段(ACK=1,确认号ack=y+1,序号seq=x+1,初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号,TCP连接已经建立,当B收到A的确认后,也进入ESTABLISHED状态。
可以看到,三次握手过程中,A的状态变化为 CLOSED->SYN-SEND->ESTABLISHED。B的状态变化为(CLOSED)LISTEN->SYNC-RECEIVED->ESTABLISHED,两者都经过3次状态变化。
为何需要最后的客户端应答(为什么需要第三次握手)?
-
第三次握手是一次客户端应答服务端确认消息的过程,是服务器端验证客户端是否在线的必要步骤。主要为了防止已失效的连接请求报文段突然又传送到了B,因而产生错误。
考虑只有两次握手,则服务端在收到请求后就已经是ESTABLISHED状态,而客户端由于各种原因未收到或断开连接,则服务端会处于等待状态,导致无效连接和资源浪费
- 客户端A向服务端B发送释放报文段(FIN=1,序号seq=u),并停止再发送数据,进入FIN-WAIT-1(终止等待1)状态,等待B的确认。
2.B收到连接释放报文段后发出确认收到的报文段(ACK=1,确认号ack=u+1,序号seq=v),B进入CLOSE-WAIT(关闭等待)状态,此时的TCP处于半关闭状态,A到B的连接释放,但B还可以向A发送数据。
A收到B的确认后,进入FIN-WAIT-2(终止等待2)状态,等待B发出的连接释放报文段。3.B在没有要向A发出的数据后,B发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),B进入LAST-ACK(最后确认)状态,等待A的确认。此时AB之间不能再有数据传输。
4.A收到B的连接释放报文段后,对此发出确认连接释放的报文段(ACK=1,seq=u+1,ack=w+1),A进入TIME-WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,A才进入CLOSED状态。B在收到A的确认连接释放报文后关闭TCP,状态进入CLOSED。
MSL =Maximum Segment Lifetime 最大报文段生存时间,也就是一个报文请求发送后到判定丢包的最大时间。
-
为什么客户端最后一次挥手后需要等待2MSL?
我们必须考虑网络是不可靠因数,有可能会出现最后一个报文丢失的情况。所以TIME_WAIT状态就是用来给服务端B的第三次挥手后进行判定重发的一个缓冲时间。1.确保A发送的请求能够到达B,这样B会正确关闭。B在发送第三次挥手(B->A连接释放报文)之后,若在2MSL内没有收到A->B的确认释放报文,则会重新发送第三次挥手。这时若A在收到第一次请求后直接关闭而没有(TIME-WAIT)等待2MSL的等待阶段,则会导致B处在(CLOSE-WAIT)状态。
2.AB之间的前后两次连接不会出现已经失效的连接中的报文出现在有效连接中。也即连接串包问题。
若A没有等待,则收到请求后直接断开,此时立即建立A->B的新连接。而B->A之间有可能还有因为网络延迟等原因产生的数据咋网络中遗留,而A和B之间又建立了新的连接。此时老的数据报文会与新的数据报文同时出现在新连接中,可能会出现数据冲突 为什么连接的时候是三次握手,关闭的时候却是四次握手?
注意第二次挥手中的A和B的状态,第二次挥手是B->A确认B进入关闭等待(CLOSE-WAIT状态,报文为ACK而无FIN),B有可能还有缓存数据需要发送给A,因此A需要进入(FIN-WAIT-2)状态,可以继续接受B->A的信息,只有在B确认好没有消息要发送后,才会发送真正的连接释放报文(FIN),因此会多出一次确认挥手,变成了4次挥手。