这张图是我们学习TCP三次握手和四次挥手的宝贝!!
三次握手
1.第一次握手:建立连接。客户端发送连接请求报文段,将SYN置为1,Sequence Number为x;之后客户端进入SYN_SENT状态,等待服务端的确认。
2.第二次握手:服务器收到请求连接报文段之后,需要对这个报文段进行确认,设置ACK的值为x+1;同时还要发送自己的SYN请求信息,将SYN设置为1,seq值设为y;将这些信息放到一个报文段中一并发给客户端,此时,服务端进入SYN_RECV状态。
3.第三次握手:客户端收到服务器的SYN+ACK报文段,然后将ACK设置为y+1,向服务端发送ACK报文段,发送之后,客户端和服务端一并进入ESTABLISHED状态,完成三次握手。
为什么TCP建立连接需要三次握手?
首先有个很有意思的小故事,很久以前有三个军阀A、B、C,
A、B是红军联盟,C是蓝军,其中C的军事实力强大,只有A和B联合起来才能打败C。在一次军事行动中,A要和B一起进攻C,但是如果A或者B单独行动的话都会被C消灭,所以在行动前A和B一定要商定好同时行动。这个时候A和B就要进行沟通,但是当时沟通不方便,只能通过写信的方式联系。
首先,A向B写一封信,信中描述了自己的意向以及什么时候行动,然后B向A回了一封信,说自己知道了,并且可以准时行动。这相当于TCP连接的前两次握手,如果没有第三次握手,这个通信就已经完成了,但是B并不能确定A是否收到了自己的信件,如果没有收到的话,A就一定不会率先行动,所以需要A再向B发送一个我确认已经收到你的信息的信,这样才能保证两军同时行动。
当然,这个故事其实就是想说TCP连接不能没有第三次握手,否则就不是一个完整的通信。真正的原因其实是因为怕服务端浪费太多资源。
当客户端发送连接请求后,这个报文段并没有消失,而是因为某些原因在网络中长时间滞留,客户端因为长时间没有收到确认报文段所以重发连接请求,这个时候之前的连接请求已经失效,但是在一段时间之后,在网路中滞留的连接请求到达服务端,服务端会认为这是客户端的一次新的连接请求,如果没有第三次握手,只要服务端确认连接就已经确立,那么服务端就会建立一个新的连接,但是因为客户端没有发出新的连接请求,所以不会理睬这个连接,也不会发送数据,而服务端会一直在等待客户端发送数据,这就导致资源的浪费,所以需要有第三次连接确认,如果客户端不给服务端发出确认报文段,服务端就不会建立新的连接。防止了上述情况的发生。
四次挥手
1.第一次挥手:主动关闭连接的一方主机1(可以是客户端,也可以是服务端),设置Seq和ACK的值,向另一个主机(主机2)发送一个FIN报文段,主机1进入FIN_WAIT_1状态,表示主机1已经没有需要发送的数据了,等待主机2的确认。
2.第二次挥手:当主机2接收到主机1发来的FIN报文后会给主机1回应一个ACK报文,此时主机2进入CLOSE_WAIT状态,在这个状态检查是否还有数据需要发送给主机,如果没有的话就可以close()这个socket并发送FIN报文,即等待你关闭连接。回应给主机1ACK报文后,主机1进入FIN_WAIT_2状态。虽然FIN_WAIT_1和FIN_WAIT_2状态的含义都是等待对方的FIN报文,但是FIN_WAIT_1状态是当SOCKET在ESTABLISHED状态的时候向主动关闭这个连接向另外一个主机发送FIN报文后进入FIN_WAIT_1,当对方回应ACK之后就会马上进入FIN_WAIT_2状态,所以一般FIN_WAIT_1很难见到。
3.第三次挥手:当主机2也没有数据需要发送的时候,主机2回向主机1也发送FIN报文,并设置Seq值,之后进入LAST_ACK状态,表示等待最后一次确认,确认过后这次连接就已经处于CLOSED状态。
4.第四次挥手:当主动关闭连接的一方也收到FIN报文段的时候进入TIME_WAIT状态,表示收到了对方的FIN报文,向主机2发送ACK报文。TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在网络中能够存活的最长时间),TIME_WAIT状态存在的意义是担心发出的ACK报文没有在主机2发送FIN报文段后最大等待时间内到达主机2,这个时候主机2会向主机1重发FIN报文,当主机1在2*MSL时间内收到FIN报文段就再向另一个主机发送ACK报文,否则两个主机都进入CLOSED状态,表示这次socket连接彻底关闭。
TIME_WAIT状态存在的理由
1)可靠的实现TCP全双工连接的终止
当主动发出FIN报文的主机也收到FIN报文时,会向另一端的主机发送ACK报文,如果没有TIME_WAIT状态的话主动发出FIN报文段的这个主机在发出ACK报文之后就处于CLOSED状态,已经关闭了连接。但是如果发出的ACK报文在网络中丢失的话,另一端的主机不能确认连接是否真的终止,要想防止这种现象,实现TCP全双工连接的终止,就需要有TIME_WAIT的存在。
2)允许老的重复分节在网络中消逝
当主机2向主机1 发送FIN报文后,如果FIN报文在网络中滞留,在超时等待后主机2会重新发送FIN报文,这样顺利关闭了这个连接。如果没有TIME_WAIT状态,在关闭就连接后马上又重新建立一个新的连接,但是当过一段时间之后,在网络中滞留的FIN报文也到达了主机1,这个报文会被新连接接收,为了避免这种情况的发生,TCP协议不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2*MSL,就可以保证当成功建立一个新的TCP连接的时候,来自旧连接的重复分节已经在网络中消逝。