在网络通信的世界里,TCP(Transmission Control Protocol,传输控制协议)是一种非常重要的协议,它确保了数据在网络中的可靠传输。而 TCP 的连接建立(握手)和连接断开(挥手)过程有着特定的步骤和逻辑,其中握手需要 3 次,挥手需要 4 次,这背后蕴含着深刻的原理。
一、TCP 握手的 3 次过程及原理
-
第一次握手:
- 客户端向服务器发送一个带有 SYN(Synchronize Sequence Numbers,同步序列号)标志的数据包,这个数据包中还包含一个随机生成的初始序列号(Sequence Number),记为 seq = x。此时客户端进入 SYN_SENT(同步已发送)状态。
- 这一步的作用是客户端告诉服务器,“我想要建立连接”,并且通过发送初始序列号,为后续的数据传输做准备。这个序列号在后续的数据包确认和排序中起着关键作用。
-
第二次握手:
- 服务器收到客户端的 SYN 数据包后,需要向客户端回应一个数据包。这个数据包包含两个关键信息:一是 SYN 和 ACK(Acknowledgment,确认)标志都被置位,二是服务器自己的初始序列号,记为 seq = y,同时确认号(Acknowledgment Number)设置为客户端的序列号加一,即 ack = x + 1。此时服务器进入 SYN_RCVD(同步收到)状态。
- 这一步的意义在于服务器告诉客户端,“我收到了你的连接请求,并且我也同意建立连接”。服务器发送自己的初始序列号是为了在后续的通信中标识自己发送的数据,而确认号的设置是对客户端发送的序列号的确认,表示服务器已经成功接收到了客户端的数据包,期待下一个序列号为 x + 1 的数据包。
-
第三次握手:
- 客户端收到服务器的回应数据包后,再向服务器发送一个 ACK 数据包,这个数据包的确认号为服务器的序列号加一,即 ack = y + 1,此时客户端进入 ESTABLISHED(已建立连接)状态。服务器收到这个 ACK 数据包后,也进入 ESTABLISHED 状态,至此,TCP 连接建立成功。
- 这一步是客户端对服务器回应的确认,告诉服务器,“我已经收到了你的同意建立连接的数据包,我们可以开始数据传输了”。通过三次握手,客户端和服务器之间就建立了一个可靠的双向连接,双方都知道了对方的初始序列号,并且可以根据序列号对数据包进行排序和确认,确保数据的正确传输。
二、为什么 TCP 握手需要 3 次而不是 2 次或 4 次?
-
不是 2 次的原因:
- 如果只进行 2 次握手,当客户端发送的第一个连接请求数据包在网络中延迟了一段时间后才到达服务器,而此时客户端可能因为长时间没有收到服务器的回应已经重新发送了一个新的连接请求并成功建立了连接,完成了数据传输后关闭了连接。但是,那个延迟的连接请求数据包此时到达了服务器,服务器会误以为这是一个新的连接请求,并向客户端发送回应数据包,建立连接。而客户端此时并不会理会这个连接,因为它已经完成了任务并关闭了相关资源,这样就会导致服务器浪费资源等待一个不存在的连接。
- 3 次握手可以很好地避免这种情况,因为第三次握手是客户端对服务器回应的确认,如果客户端没有发送第三次握手的数据包,服务器就会知道这个连接请求可能是无效的或者已经超时,从而不会建立连接,避免了资源的浪费。
-
不是 4 次的原因:
- 3 次握手已经能够满足可靠建立连接的需求。在第三次握手时,客户端已经向服务器确认了连接请求,并且双方都知道了对方的初始序列号,具备了开始数据传输的条件。如果再增加一次握手,会增加通信的开销和延迟,而没有实际的必要。经过多年的实践和研究证明,3 次握手是在保证连接可靠性的前提下最有效的方式。
三、TCP 挥手的 4 次过程及原理
-
第一次挥手:
- 当客户端想要关闭连接时,它会向服务器发送一个带有 FIN(Finish,结束)标志的数据包,表示客户端不再发送数据,但仍然可以接收数据。此时客户端进入 FIN_WAIT_1(终止等待 1)状态。
- 这一步是客户端主动发起的关闭连接请求,告诉服务器它已经完成了数据的发送,希望结束数据传输的阶段。
-
第二次挥手:
- 服务器收到客户端的 FIN 数据包后,会向客户端发送一个 ACK 数据包,表示服务器已经收到了客户端的关闭请求,并且确认客户端之前发送的数据都已经成功接收。此时服务器进入 CLOSE_WAIT(关闭等待)状态,客户端收到这个 ACK 数据包后进入 FIN_WAIT_2(终止等待 2)状态。
- 这一步是服务器对客户端关闭请求的确认,让客户端知道它的请求已经被服务器接收,并且服务器正在处理剩余的数据。
-
第三次挥手:
- 服务器处理完剩余的数据后,也会向客户端发送一个带有 FIN 标志的数据包,表示服务器也完成了数据的发送,希望关闭连接。此时服务器进入 LAST_ACK(最后确认)状态。
- 这一步是服务器主动发起的关闭连接请求,告诉客户端它也已经完成了所有的数据处理工作,准备结束连接。
-
第四次挥手:
- 客户端收到服务器的 FIN 数据包后,会向服务器发送一个 ACK 数据包,确认服务器的关闭请求。此时客户端进入 TIME_WAIT(时间等待)状态,经过一段时间后(这个时间通常是 2 倍的最大段生存期,即 2MSL),客户端才会进入 CLOSED(关闭)状态。服务器收到这个 ACK 数据包后,直接进入 CLOSED 状态,至此,TCP 连接完全关闭。
- 这一步是客户端对服务器关闭请求的最终确认,确保双方都能够正常关闭连接。而客户端进入 TIME_WAIT 状态的目的是为了防止最后一个 ACK 数据包丢失,如果丢失,服务器会重新发送 FIN 数据包,客户端在 TIME_WAIT 状态下可以重新发送 ACK 数据包进行确认。
四、为什么 TCP 挥手需要 4 次而不是 3 次?
-
数据传输的双向性:
- TCP 连接是全双工的,即数据可以在两个方向上同时传输。在关闭连接时,客户端和服务器都可能还有未发送完的数据需要继续发送。当客户端发送 FIN 数据包表示它不再发送数据时,服务器可能还有数据要发送给客户端,所以服务器需要先发送 ACK 数据包确认客户端的关闭请求,然后再发送 FIN 数据包表示自己也准备关闭连接。
- 这就导致了在关闭连接的过程中,需要分别处理客户端到服务器和服务器到客户端两个方向的数据传输结束的情况,所以需要 4 次挥手来确保双方都能够正确地关闭连接。
-
保证数据的完全传输:
- 在服务器收到客户端的 FIN 数据包后,它需要时间来处理剩余的数据,并确保这些数据都已经成功发送给客户端。因此,服务器不能立即关闭连接,而是需要先发送 ACK 数据包确认客户端的请求,然后在处理完剩余数据后再发送 FIN 数据包。这样可以保证数据的完整性和可靠性,避免数据丢失。
- 如果采用 3 次挥手,可能会导致服务器在还有数据未发送完的情况下就被强制关闭连接,从而造成数据丢失或者传输错误。
通过以上对 TCP 握手和挥手机制的详细解析,我们可以清楚地了解到为什么握手是 3 次,挥手是 4 次。这些机制是为了确保 TCP 连接的可靠性、数据的正确传输以及资源的合理利用。理解这些原理对于网络开发人员、系统管理员以及对网络通信感兴趣的人来说都非常重要,它有助于我们更好地理解网络通信的本质,解决网络连接中的各种问题,提高网络应用的性能和稳定性。
文章(专栏)将持续更新,欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发。
个人小工具程序上线啦,通过公众号(服务端技术精选)菜单【个人工具】即可体验,欢迎大家体验后提出优化意见!