深度解析TCP三次握手四次挥手

引言

在网络编程和日常技术面试中,TCP(传输控制协议)的"三次握手"和"四次挥手"是绕不开的核心知识点。它们分别是建立连接和断开连接的两个重要过程。

很多同学都能背出"三次握手建立连接,四次挥手断开连接",但对于"为什么挥手非要四次而不是三次?"、"TIME_WAIT状态为什么要等那么久?"等问题却一知半解。

今天,我们就以客户端主动断开连接的场景为例,结合你提供的清晰笔记,深入浅出地把这些过程、状态变化以及背后的设计原理讲明白。


第一部分:TCP四次挥手------优雅地说再见

当客户端的数据发送完毕,想要主动关闭连接时,就需要通过"四次挥手"来结束这段双向通信。

前提条件: 初始状态,客户端和服务端都处于 ESTABLISHED(连接已建立)状态。

第一次挥手:客户端发起关闭

  • 动作: 客户端在确认没有数据要发送后,向服务端发送一个 FIN(Finish,结束)报文段,用来关闭客户端到服务端的数据传输。

  • 状态变化:

    • 客户端: ESTABLISHED ------> FIN_WAIT_1(终止等待1)

第二次挥手:服务端确认关闭

  • 动作: 服务端收到 FIN 报文后,知道客户端要断开连接了。服务端先发送一个 ACK(Acknowledgment,确认)报文作为应答。

  • 状态变化:

    • 服务端: ESTABLISHED ------> CLOSE_WAIT(关闭等待)

    • 客户端收到 ACK 后: FIN_WAIT_1 ------> FIN_WAIT_2(终止等待2)

  • 此时连接状态: 从客户端到服务端这个方向的连接已经关闭了,客户端没有数据要发了。但从服务端到客户端这个方向还是打开的,服务端如果有未发完的数据,可以继续发送。

第三次挥手:服务端最后的数据发完了

  • 动作: 服务端将剩余数据都发送完毕后,确认自己没有东西要发了,于是向客户端发送 FIN 报文,用来关闭服务端到客户端的数据传输。

  • 状态变化:

    • 服务端: CLOSE_WAIT ------> LAST_ACK(最后确认)

第四次挥手:客户端最终确认

  • 动作: 客户端收到服务端的 FIN 报文后,知道数据全部接收完毕,发送最后一个 ACK 报文作为应答。

  • 状态变化:

    • 客户端: FIN_WAIT_2 ------> TIME_WAIT(时间等待)

    • 服务端收到 ACK 后: LAST_ACK ------> CLOSED(完全关闭)

  • 最终收尾: 客户端在 TIME_WAIT 状态等待 2MSL (最大报文段生存时间)后,自动变为 CLOSED 状态。


第二部分:挥手过程中的"灵魂三问"

1. 为什么挥手是四次,而不是像握手一样是三次?

这就是你笔记中提到的关键点:ACK和FIN报文不能同时发

  • 在三次握手中 ,服务端收到客户端的SYN请求后,可以立即回复 SYN + ACK 报文,因为"同意建立连接"和"我自己的同步请求"这两个动作可以一次性完成。

  • 在四次挥手中 ,当服务端收到客户端的 FIN 报文时,它可能还有数据没传完。因此,它不能马上关闭连接,只能先回复一个 ACK,告诉客户端"我知道你要关了,你先等着,等我处理完手头的数据再关"。

  • 直到服务端把数据都发完了,才会发送自己的 FIN 报文。这就导致了 ACKFIN 是分开发送的,因此需要四次交互。

简单来说:握手时两手都要握,可以同时伸手;挥手时需要等对方把手头上的事干完才能一起挥,所以多了一步。

2. 为什么需要 TIME_WAIT 状态?为什么要等待 2MSL?

TIME_WAIT 是 TCP 协议设计中非常精妙的一环,它的主要作用有两个:

  1. 确保最后的 ACK 能被服务端收到(可靠关闭):

    • 如果最后一次握手的 ACK 报文在网络中丢失了,服务端在超时后会重发 FIN 报文。

    • 如果客户端发送完 ACK 后就直接 CLOSED 了,那么它就无法响应服务端重发的 FIN,会导致服务端一直处于 LAST_ACK 状态而无法关闭。

    • 客户端进入 TIME_WAIT 状态,就是为了"等"一下,处理这种意外情况,重新发送 ACK,确保服务端能安全关闭。

  2. 防止旧连接的报文干扰新连接(2MSL的意义):

    • MSL(Maximum Segment Lifetime) 是报文在网络中的最大存活时间。

    • 等待 2MSL 的时间,可以保证本次连接的所有旧报文(比如因为网络延迟,现在才到的数据包)都在网络中消失,不会出现在下一次使用相同四元组(源IP、源端口、目的IP、目的端口)的新连接中,从而避免数据混乱。


第三部分:TCP三次握手------建立可靠的连接

了解了挥手,我们再简单回顾一下建立连接的三次握手过程,以便对比理解。

前提条件: 服务端启动,处于 LISTEN(监听)状态。

第一次握手:客户端发起连接

  • 动作: 客户端发送 SYN(同步)报文,并生成一个随机序列号。

  • 状态变化:

    • 客户端: CLOSED ------> SYN_SENT(同步已发送)

第二次握手:服务端同意连接

  • 动作: 服务端收到 SYN 后,如果同意建立连接,会发送 SYN-ACK 报文(包含对客户端报文的确认号和自己的序列号)。

  • 状态变化:

    • 服务端: LISTEN ------> SYN_RCVD(同步已接收)

第三次握手:客户端最终确认

  • 动作: 客户端收到 SYN-ACK 后,检查确认号是否正确。正确后,客户端状态变为 ESTABLISHED,并发送一个 ACK 报文作为最终确认。此时,连接建立成功,可以开始传输数据。

  • 状态变化:

    • 服务端收到 ACK 后: SYN_RCVD ------> ESTABLISHED

第四部分:握手中的关键问题------为什么必须是三次?

问题:两次握手不行吗?

答案:绝对不行。 核心原因是为了防止已失效的连接请求报文段突然又传到服务端,从而产生错误。

  • 场景模拟:

    1. 客户端发送了一个 SYN 报文,因为网络拥堵,这个报文滞留在了某个网络节点。

    2. 客户端以为这个报文丢了,于是重传了一个 SYN,这次成功建立连接并传输完数据后关闭了。

    3. 就在这时,那个被滞留的旧 SYN 报文突然到达了服务端。

    4. 如果是两次握手 :服务端收到这个过时的 SYN 报文,会认为客户端想要建立新连接,于是直接回复 SYN-ACK,并进入 ESTABLISHED 状态,等待客户端发送数据。但客户端根本不知道这回事,也不会理会这个连接。这就导致服务端白白耗费资源,一直等待着一个根本不存在的连接(半开连接)。

    5. 如果是三次握手 :服务端收到过时的 SYN 报文,回复 SYN-ACK。客户端收到后,发现确认号不是自己预期的,就知道这是一个过时的连接,于是发送 RST(复位)报文告诉服务端终止这个连接。这样服务端收到 RST 后就会释放资源,不会傻等。

三次握手是防止历史重复连接初始化造成混乱的最小次数,保证了连接的可靠性和资源不被浪费。


第五部分:知识拓展------TCP与UDP的世纪对决

聊了这么多TCP的细节

,我们再来看看它和UDP的区别,以及如何在实际场景中选择它们。

TCP vs UDP:核心区别对比

特性 TCP (传输控制协议) UDP (用户数据报协议)
连接状态 面向连接(需三次握手) 无连接(直接发送)
可靠性 可靠传输(有确认、重传、排序机制) 不可靠传输(尽最大努力交付)
传输方式 面向字节流(无边界) 面向数据报(有边界,可能丢失或乱序)
效率与开销 效率低,头部开销大(20字节) 效率高,头部开销小(8字节)
流量/拥塞控制
应用场景 对准确性要求高:文件传输、邮件、网页浏览、数据库连接等 对实时性要求高:视频直播、语音通话、DNS查询、广播等

什么时候用TCP?

你需要确保数据100%准确无误地送达对方,即使慢一点也可以。

  • 例子: 下载文件、浏览网页、发送邮件、量化交易系统(虽然追求速度,但数据准确性是底线)、高性能服务间调用。

什么时候用UDP?

你需要速度快,可以容忍偶尔的数据丢失或少许花屏,但不能有太大的延迟。

  • 例子: 视频会议、网络直播、在线游戏(位置信息)、物联网设备上报心跳包。

总结

TCP作为一个可靠的传输协议,无论是建立连接的"三次握手",还是断开连接的"四次挥手",其每一步的设计都充满了智慧,旨在复杂的网络环境中保证数据传输的准确性和可靠性。

  • 三次握手是为了防止历史重复连接的初始化错误。

  • 四次挥手 是由于TCP的全双工特性,允许一端关闭后另一端继续发送数据,并通过 TIME_WAIT2MSL 保证了连接可靠关闭和避免新旧数据混淆。

理解这些底层原理,不仅能帮我们应对面试,更能在实际遇到网络问题时,帮助我们快速定位和解决问题。希望这篇文章对你有所帮助!

相关推荐
双手插兜-装高手2 小时前
C++设计模式
c++·设计模式
星轨初途2 小时前
郑州轻工业大学“筑梯杯” 2025级新生程序设计大赛暨省内高校邀请赛——题解
android·c++·经验分享·笔记·算法
淮南颂恩少儿编程2 小时前
淮南少儿编程 | CSP-J真题详解:在淮南也有接地气的算法课
c++·人工智能·python·深度学习·算法·青少年编程·蓝桥杯
m0_748873552 小时前
模板编译期排序算法
开发语言·c++·算法
2401_842623652 小时前
基于C++的爬虫框架
开发语言·c++·算法
无限进步_2 小时前
【C++】获取字符串最后一个单词长度的多种解法
开发语言·c++·ide·windows·git·github·visual studio
杰杰7982 小时前
一文了解DRF——ModelSerializer
后端·django
万象.2 小时前
Linux网络层相关知识及报文格式
linux·网络·智能路由器
盛世宏博北京2 小时前
6. 物联网环境监测新标杆:POE供电以太网温湿度变送器技术详解
大数据·运维·网络·以太网·poe·温湿度变送器