上次我们介绍了TCP链接的三次握手,这次我们来说一下TCP的四次挥手。 三次握手是在创建连接,那顾名思义四次挥手就是在断开连接的。 当我们两个主机想要断开连接的时候就通过四次通信来断开一个存在的TCP链接。那为什么需要四次挥手来断开连接呢?我们先说一下四次挥手的过程。 第一次挥手:主动关闭的一方向A向被动的一方B发送断开请求,在发送数据包的时候把TCP首部的FIN设置为1,ACK设置为1,seq设置为X,也就是上次对方发送过来的ACK值,ACK设置为上次对方传来的Seq+1,这时候把数据包发送给被动方B,然后A就会进入FIN_WAIT_1状态,等待被动关闭方B的回应。 第二次挥手:被动关闭的一方B收到了A发送来的FIN包,明白了A要关闭,这时候B就需要向A做出回复,将标志符ACK设置为1,然后把ACK数值设置为A发来的seq+1,seq设置为A发来的ACK值,然后B进入到CLOSE_WAIT,当A收到B的这个回复之后就会进入FIN_WAIT_2状态。 第三次挥手:B再次向A发送报文, 就是告诉A我也要关了,把首部的FIN值设置为1,ACK设置为1,然后Ack数值设置为,第二次握手时的Ack,Seq设置为第二次握手中的seq。然后B就进入LAST_ACK,状态,当A收到B的这一条报文之后,就会进入TIME_WAIT状态。 第四次挥手:A收到B发送的第三次挥手的FIN报文段之后,会和第二次握手B回复A一样,回复B一个报文,将ACK设置为1,ack为第三次挥手中的seq+1.seq设置为第三次挥手中的ack+1,然后A就进入了TIME_WAIT状态,B在收到A这次发的报文之后会进入CLOSED状态,当A在发送完这个报文之后等到2MSL时间之后就会进入CLOSED状态。 先说一下上边提到的这些状态,A经历的FIN_WATI_1和FIN_WAIT_2顾名思义就是在等待B发送,B的FIN报文。FIN_WAIT_1是A发送给B关闭链接的请求之后,A就进入这个状态,这个状态表示A已经没有数据要发送了,但是仍然可以接受数据。FIN_WAIT_2这时候SOCKET是处于半链接状态,只不过是A收到了B对自己关闭链接请求的回复。 CLOSE_WAIT是B在给A的FIN包做出应答之后,在B发送FIN包之前会做检查, 看还有没有数据要发送,如果有的话就先发送数据,如果没有的话就发送FIN包,这个状态下是B在等待做完自己的工作,然后在准备关闭链接。 LAST_WAIT就是B在发送完FIN包之后,等待A的响应。就会进入这个状态,当收到A的回应之后就直接CLOSE了、 TIME_WAIT当A收到了B发送的报文之后,用ACK进行回复,就进入TIME_WAIT就是等待关闭的状态,就差最后一步关掉了,当A发完对B发送的FIN报文的应答之后,就会进入TIME_WAIT状态,等2MSL时长之后,A就进入了CLOSED状态彻底关闭了。 为什么要等待2MSL之后再关闭链接? 我们注意在第四次握手的时候A发送对B的FIN包请求的应答之后并没有直接关闭而是等待了2MSL时间才关闭,2MSL全称是Maximum Segment Life也就是最大生存时间,就是A等待了TCP数据包在网络上两个最大生存时间之后才关闭。 我们为什么说TCP是可靠的?之前就介绍过了TCP的可靠不是说我能保证我某一次发送的数据包你一定能收到,一定没有问题,而是你有问题的话我会重新给你发,保证你最后接受到拼凑起来的数据是没有问题,因为网络传输过程中,数据是很有可能丢失的,这里也一样,如果我们A发送了给B最后一个确认应答之后,就直接关闭,那这个数据包丢了怎么办?所以如果说B收不到自己的FIN包的确认应答, B就会超时重传这个FIN包,而A就能在这2MSL时间里边再次收到这个报文,然后A会再次发送一次确认应答, 并且把2MSL计时器进行重置。不然如果数据包丢失B重发了,而A直接关了,没有收到,那B就没有办法正确的CLOSED步骤。并且这样也能防止失效的数据包出现在下一次新的链接里边,经过2MSL会让本次链接的所有数据包都从网络中小时,这样下一个新的链接就不会有这次链接的数据包。 和三次握手一样,为什么要进行四次挥手?为什么不能把第二次第三次握手合成一次? 上边我们也介绍了,当B收到A的FIN包之后会对他进行相应,但是并不一定会马上发送自己的FIN包给A因为很有可能B还有数据没有发送给A,如果合成一个的话,那自然会导致一些数据的丢失。