一、什么是 TCP 的三次握手和四次挥手?
- 三次握手:就像两个人初次见面打招呼并确认可以交流的过程。客户端相当于一个人,服务器相当于另一个人。首先客户端向服务器说 “你好,我想和你交流”(发送 SYN 报文),这是第一次握手;服务器听到后回应 “你好,很高兴认识你,我也可以和你交流”(发送 SYN+ACK 报文),这是第二次握手;客户端再回应 “好的,那我们开始交流吧”(发送 ACK 报文),这是第三次握手。经过这三次握手,双方就建立起了可靠的 TCP 连接,可以开始传输数据了。发送 回应 确认好的
- 四次挥手:如同两个人交流完后互相告别。一方先说 “我说完了,我要走了”(主动关闭方发送 FIN 报文),这是第一次挥手;另一方回应 “好的,我知道了,等我一下”(发送 ACK 报文),这是第二次挥手;等另一方也说完了,就会说 “我也说完了,我们可以分开了”(发送 FIN 报文),这是第三次挥手;主动关闭方最后回应 “好的,再见”(发送 ACK 报文),这是第四次挥手。经过这四次挥手,双方就安全地关闭了 TCP 连接。 发送 回应等一下 回应好了 确认好的
二、为什么要有三次握手和四次挥手?
为什么要有三次握手而不是两次?
- 防止已失效的连接请求报文突然又传送到了服务器:
- 假设只有 “发送” 和 “回应” 两次握手。如果客户端发送的第一个连接请求报文在网络中滞留了,迟迟没有到达服务器。客户端在一段时间后超时重传了另一个连接请求报文,这次服务器正常接收并回应,双方建立了连接并开始数据传输,传输结束后关闭了连接。
- 但此时,那个滞留的第一次连接请求报文突然到达了服务器。服务器以为是一个新的连接请求,于是回应并进入等待客户端数据传输的状态。但客户端此时并没有发起新的连接请求,就不会对服务器的回应进行处理,这就导致服务器一直等待,浪费了服务器的资源。
- 确保双方都做好了建立连接的准备:
- 经过三次握手,客户端和服务器都能确认对方的接收和发送能力正常。
- 第一次握手,客户端向服务器发送 SYN 报文,表示客户端有发送数据的能力,并且希望建立连接。
- 第二次握手,服务器回应 SYN+ACK 报文,表示服务器有接收和发送数据的能力,并且同意建立连接。
- 第三次握手,客户端回应 ACK 报文,表示客户端确认了服务器的接收和发送能力,并且双方可以开始数据传输了。
客户端就像是一个人 A,服务器就像是另一个人 B。A 给 B 写信说想一起做个项目(相当于客户端发送连接请求报文)。但是这封信在邮寄过程中出了问题,被耽搁在了路上。A 等了好久没收到回复,以为信丢了,于是又写了一封信给 B(相当于超时重传连接请求报文)。B 收到了第二封信,很高兴地回信说可以一起做项目(服务器回应连接请求)。然后他们就开始准备项目,等项目做完了,合作关系结束。
可这时候,第一封信突然到了 B 那里。B 以为 A 又想和他做新的项目呢,于是赶紧回信说可以(服务器对滞留的连接请求报文回应),然后 B 就开始准备新的项目,等着 A 进一步的指示。但实际上 A 根本不知道第一封信这时候才到,也没有要开启新合作的打算。
在这个例子中,B 因为收到了滞留的信而做了很多无用功,浪费了时间和精力去准备一个根本不会开始的项目。就像服务器因为收到滞留的连接请求报文而进入等待状态,分配了资源准备接收数据,但实际上客户端并不会发来数据。服务器在这段时间里不能处理其他真正有效的连接请求,白白浪费了服务器的资源,比如内存空间用来存储这个可能的连接状态信息、CPU 时间用来时不时检查这个连接是否有数据传来等。这就是滞留的连接请求报文可能导致的资源浪费情况。
四次挥手的原因:
四次挥手是在关闭 TCP 连接时,客户端和服务器之间进行的四次信息交换过程。就像两个人合作完成后要结束合作关系,需要互相告知并确认双方都做好了结束的准备。
- 为什么不能是两次挥手
-
全双工通信需要双方都确认:TCP 连接是全双工的,意味着双方可以同时进行数据的发送和接收。当一方想要关闭连接时,只是表明它自己没有数据要发送了,但不能确定对方是否也没有数据要发送了。
例如,A 和 B 两个人在通话,A 说 “我说完了,挂电话吧”,然后直接挂断。但此时 B 可能还有话要说,这样就会导致 B 的话没有机会说出来。在 TCP 中,如果只有两次挥手,主动关闭方发送 FIN 表示自己没有数据要发送了,然后被动关闭方回应 ACK 后就直接关闭连接,可能会导致被动关闭方还有未发送完的数据丢失。 -
确保数据传输的完整性:TCP 要保证数据的可靠传输,在关闭连接时也需要确保所有的数据都已经被正确接收和处理。
如果只有两次挥手,主动关闭方发送 FIN 后,被动关闭方回应 ACK 并立即关闭连接,可能会出现被动关闭方在回应 ACK 后又接收到了主动关闭方之前发送的一些数据,但此时连接已经关闭,无法正确处理这些数据。
-
三、为什么不能是三次挥手
- 双方都需要确认自己和对方的状态:四次挥手的过程中,主动关闭方发送 FIN 表示自己没有数据要发送了,被动关闭方回应 ACK 表示知道了主动关闭方的请求,然后被动关闭方也发送 FIN 表示自己也没有数据要发送了,主动关闭方再回应 ACK 表示知道了被动关闭方的请求。这个过程确保了双方都明确了对方的状态,并且都做好了关闭连接的准备。
- 如果是三次挥手,可能会出现这样的情况:主动关闭方发送 FIN,被动关闭方回应 ACK 和 FIN 一起发送,表示自己知道主动关闭方的请求并且自己也没有数据要发送了。但是这样主动关闭方无法确定被动关闭方是否真的已经处理完了所有的数据,因为被动关闭方可能在发送 ACK 和 FIN 之后又接收到了一些数据。
-
还是用两个人通电话来比喻。A 对 B 说要挂电话(A 发送 FIN),B 回应知道了等一下(B 发送 ACK),然后 B 确定自己也说完了又对 A 说可以挂了(B 发送 FIN)。如果 A 不回应 “好的,挂吧”(A 发送 ACK),那么 B 就不知道 A 是否真的收到了自己说可以挂电话的消息。就像 B 一直在等 A 的确认,只有确认后 B 才能放心地认为这次通话真的结束了,否则 B 可能会一直处于等待状态,不知道连接是否已经完全关闭,也可能会因为不确定而再次尝试发送结束通话的消息,造成混乱
- 确保连接可靠关闭:TCP 是一种可靠的传输协议,需要通过四次挥手来确保双方都能正确地关闭连接。A 发送的最后一个 ACK 报文是对 B 发送的 FIN 报文的确认,让 B 知道 A 已经收到了它的关闭请求,并且 A 也没有更多的数据要发送了。如果没有这个 ACK 报文,B 可能会认为自己发送的 FIN 报文丢失了,从而重新发送 FIN 报文,导致连接无法正常关闭。
- 防止数据丢失:在网络中,报文可能会因为各种原因丢失、延迟或重复。如果 A 不发送 ACK 报文,B 在等待一段时间后可能会重新发送 FIN 报文,而此时 A 可能已经关闭了连接,不再接收报文。这样就可能导致 B 一直重复发送 FIN 报文,浪费网络资源,也可能会影响其他连接的建立和关闭。同时,如果 A 在发送 FIN 报文后还有一些数据没有被 B 接收,B 可能会在等待 A 的 ACK 报文的过程中继续接收这些数据,确保数据的完整性。
综上所述,TCP 需要四次挥手来确保连接的安全、可靠地关闭,保证数据传输的完整性和双方都能正确地结束通信。
三、怎么理解三次握手和四次挥手的过程?
- 三次握手过程:
- 第一次握手:客户端向服务器发送一个 SYN 报文,请求建立连接,此时客户端进入 SYN_SENT 状态。
- 第二次握手:服务器收到客户端的 SYN 报文后,向客户端发送一个 SYN+ACK 报文,确认客户端的请求并同时也请求建立连接,此时服务器进入 SYN_RCVD 状态。
- 第三次握手:客户端收到服务器的 SYN+ACK 报文后,向服务器发送一个 ACK 报文,确认服务器的请求,此时客户端和服务器都进入 ESTABLISHED 状态,连接建立成功。
- 四次挥手过程:
- 第一次挥手:主动关闭方(假设是客户端)向被动关闭方(服务器)发送一个 FIN 报文,表明自己没有数据要发送了,想要关闭连接,此时客户端进入 FIN_WAIT_1 状态。
- 第二次挥手:服务器收到客户端的 FIN 报文后,向客户端发送一个 ACK 报文,确认收到客户端的关闭请求,此时服务器进入 CLOSE_WAIT 状态,客户端收到这个 ACK 报文后,进入 FIN_WAIT_2 状态。
- 第三次挥手:服务器处理完自己的事情后,也向客户端发送一个 FIN 报文,表明自己也没有数据要发送了,想要关闭连接,此时服务器进入 LAST_ACK 状态。
- 第四次挥手:客户端收到服务器的 FIN 报文后,向服务器发送一个 ACK 报文,确认收到服务器的关闭请求,此时客户端进入 TIME_WAIT 状态,服务器收到这个 ACK 报文后,进入 CLOSED 状态,客户端在经过一段时间的等待(一般为 2 倍的最大段生存期)后,也进入 CLOSED 状态,连接完全关闭。