TCP三次握手与四次挥手通俗理解


---知识点专栏---


引言

在TCP/IP协议栈中,TCP (传输控制协议)就像"网络世界的可靠信使"------它不像UDP那样"丢三落四",而是通过严谨的"握手建连"和"挥手断连",确保数据能从发送端完整、有序地抵达接收端。本文将结合文档内容,用"生活场景类比"拆解三次握手与四次挥手的细节,同时梳理关键技术点,帮你彻底搞懂这两个TCP核心机制。

一、先搞懂前提:TCP为什么需要"握手"和"挥手"?

TCP的核心特性是面向连接、可靠传输。就像现实中"寄重要快递":

  • 寄件前,你得先确认收件人"在家且能收件"(对应"握手建连",确认双方收发能力);
  • 寄完后,你得告知收件人"所有包裹已寄完,不用等了"(对应"挥手断连",确认双方无数据可传)。

如果没有这两步:要么"快递寄了没人收"(数据丢失),要么"收件人一直等包裹"(资源浪费)。文档中也明确提到,TCP的连接管理是其可靠性的关键组成部分,而三次握手与四次挥手正是连接管理的核心流程🔶1-129🔶。

二、TCP三次握手:如何"建立可靠连接"?

三次握手的本质是**"双向确认"** ------不仅要确认"我能发给你",还要确认"你能发给我,且我能收到你的回复"。我们用"两个人打电话"的场景类比,同时结合文档中的状态变化和数据交互细节拆解。

1. 参与角色与初始状态

  • 客户端 :主动发起连接的一方(比如你用浏览器访问服务器)。初始状态为CLOSED,通过socket()创建通信文件描述符后,调用connect()函数向服务器发起连接请求,进入SYN_SENT状态。
  • 服务器 :被动接收连接的一方(比如阿里云上的Web服务器)。初始状态为CLOSED,通过socket()创建listenfd(监听描述符),再经bind()绑定IP和端口、listen()开启监听后,进入LISTEN状态,等待客户端的连接请求。

2. 三次握手详细步骤:像"打电话接通"的过程

步骤 类比场景(你→朋友) 技术层面(客户端→服务器) 核心数据与标志位 双方状态变化
第一次握手("喂,你在吗?") 你拨打朋友电话,等待对方接听 客户端发送SYN报文段(同步报文),表示"我想和你建立连接" - 客户端初始序列号(Seq = x,比如x=100) - 标志位SYN=1(SYN=Synchronize,同步请求) 客户端:CLOSEDSYN_SENT(等待服务器回复) 服务器:LISTENSYN_RCVD(收到请求,准备回复)
第二次握手("我在!你能听到吗?") 朋友接起电话,回复"我在",同时确认"能听到你的声音" 服务器收到SYN后,回复SYN+ACK报文段,既同步自己的信息,又确认客户端的请求 - 服务器初始序列号(Seq = y,比如y=200) - 确认号(Ack = x+1 = 101,表示"已收到你Seq=100的报文") - 标志位SYN=1(服务器同步)+ ACK=1(ACK=Acknowledgment,确认有效) 服务器:SYN_RCVD(等待客户端最终确认) 客户端:收到后验证Ack=101(正确),进入ESTABLISHED(连接初步建立,可准备发数据)
第三次握手("能听到!那我们开始说吧") 你回复"能听到",确认双方沟通通道已通 客户端收到SYN+ACK后,发送ACK报文段,最终确认连接 - 确认号(Ack = y+1 = 201,表示"已收到你Seq=200的报文") - 标志位ACK=1(最终确认) 客户端:ESTABLISHED(连接完全建立,可发数据) 服务器:收到Ack=201(正确),进入ESTABLISHED(连接完全建立,可收/发数据)

3. 为什么是"三次"而不是"两次"?

很多人会问:第二次握手时服务器已经回复了SYN+ACK,为什么客户端还要再发一次ACK?

举个反例:如果只有两次握手,假设客户端早期发送的"失效SYN报文"(因网络延迟滞留)突然到达服务器,服务器会误以为是新的连接请求,回复SYN+ACK后直接进入ESTABLISHED状态,等待客户端发数据。但客户端知道这是失效请求,不会理会,导致服务器一直占用资源等待,造成浪费。

而三次握手的第三次ACK,能让服务器确认"客户端确实是要建立新连接",避免这种"失效连接请求"的干扰------这是TCP可靠性的重要细节。

4. 三次握手的核心意义

  1. 确认双向收发能力:客户端通过"发SYN→收SYN+ACK"确认服务器"能收能发";服务器通过"收SYN→发SYN+ACK→收ACK"确认客户端"能收能发",避免"单向通"问题。
  2. 协商初始序列号:TCP通过序列号(Seq)保证数据按序到达(比如后续发数据会从Seq=x+1、Seq=y+1开始),三次握手阶段双方交换初始序列号,为后续数据传输奠定基础。
  3. 为后续机制铺路:建立连接后,双方才能开启滑动窗口、流量控制等性能优化机制,这些都是TCP高效传输的关键。

三、TCP四次挥手:如何"安全关闭连接"?

TCP连接是全双工的------就像电话两端可以同时说话,客户端和服务器也可以同时向对方发送数据。因此关闭连接时,需要双方分别确认"我这边没有数据要发了",这就导致了"四次挥手"(三次握手因仅需同步序列号,可合并一次SYN+ACK)。

1. 参与角色与初始状态

双方均处于ESTABLISHED状态(正常通信状态),某一方(通常是客户端,比如你关闭浏览器)先发起关闭请求,成为"主动关闭方";另一方(服务器)为"被动关闭方"。

2. 四次挥手详细步骤:像"打电话挂断"的过程

步骤 类比场景(你→朋友) 技术层面(客户端→服务器) 核心数据与标志位 双方状态变化
第一次挥手("我说完了,你还有要说的吗?") 你先说完事情,告诉朋友"我这边没话说了" 客户端调用close()函数,发送FIN报文段(结束报文),表示"我已无数据可发" - 客户端当前序列号(Seq = u,比如u=500,即最后一次发数据的Seq+1) - 标志位FIN=1(FIN=Finish,结束请求) 客户端:ESTABLISHEDFIN_WAIT_1(等待服务器确认关闭) 服务器:ESTABLISHEDCLOSE_WAIT(确认收到关闭请求,此时服务器仍可向客户端发数据)
第二次挥手("好的,我知道你说完了,我再想想还有没有") 朋友回复"听到了",但可能还有事情要跟你说 服务器收到FIN后,发送ACK报文段,确认客户端的关闭请求 - 确认号(Ack = u+1 = 501,表示"已收到你Seq=500的FIN") - 标志位ACK=1(确认有效) 服务器:CLOSE_WAIT(继续发送剩余数据,比如服务器还没传完的网页内容) 客户端:收到Ack=501后,进入FIN_WAIT_2(等待服务器说"我也说完了")
第三次挥手("我也说完了,那挂了吧") 朋友说完剩余事情,告诉"我也没话说了" 服务器发送完所有数据后,调用close(),发送FIN报文段,表示"我也无数据可发" - 服务器当前序列号(Seq = v,比如v=600,即最后一次发数据的Seq+1) - 标志位FIN=1(结束请求) 服务器:CLOSE_WAITLAST_ACK(等待客户端最终确认关闭) 客户端:收到FIN后,进入TIME_WAIT(关键状态,等待2MSL时间)
第四次挥手("好的,挂吧") 你回复"好的",确认双方都没话说了 客户端收到FIN后,发送ACK报文段,最终确认关闭 - 确认号(Ack = v+1 = 601,表示"已收到你Seq=600的FIN") - 标志位ACK=1(最终确认) 客户端:TIME_WAIT(等待2MSL后进入CLOSED) 服务器:收到Ack=601后,进入CLOSED(连接完全关闭,释放资源)

3. 两个关键状态解析

(1)TIME_WAIT:为什么要等"2MSL"?
  • MSL(Maximum Segment Lifetime):TCP报文在网络中的最大生存时间(通常为1-2分钟),超过这个时间的报文会被网络丢弃。
  • 2MSL的作用 (:
    1. 确保"最后一个ACK"被服务器收到:如果客户端发送的第四次挥手ACK丢失,服务器会重发FIN;2MSL时间足够客户端收到重发的FIN,并再次发送ACK,避免服务器一直处于LAST_ACK状态。
    2. 清空网络中的"残留报文":2MSL时间能确保客户端发送的所有报文(包括最后一个ACK)都从网络中消失,避免后续新连接收到旧连接的残留报文,导致数据混乱。
(2)CLOSE_WAIT:为什么服务器会出现大量CLOSE_WAIT?

文档明确指出:服务器出现大量CLOSE_WAIT,本质是"服务器没有正确调用close()函数"------服务器收到客户端的FIN后进入CLOSE_WAIT,但因代码bug(比如忘记关闭socket),一直不发送自己的FIN,导致连接长期滞留在此状态。

解决方法很简单:检查服务器代码,确保在"无需继续发送数据"时主动调用close(),释放socket资源。

4. 为什么是"四次"而不是"三次"?

因为TCP是全双工的,关闭连接需要"双向确认":

  • 第一次和第二次挥手:客户端确认"我这边关了",服务器知道"客户端关了";
  • 第三次和第四次挥手:服务器确认"我这边也关了",客户端知道"服务器关了"。
    如果合并成三次,比如服务器在第二次挥手时同时发送FIN,可能导致服务器还有数据没发完就强制关闭,造成数据丢失------这违背了TCP可靠传输的原则。

四、三次握手与四次挥手对比(一目了然)

维度 三次握手(建立连接) 四次挥手(关闭连接)
核心目的 双向确认收发能力、协商序列号 双向确认无数据可发、释放资源
交互次数 3次(含1次SYN+ACK合并) 4次(无合并,全双工需分别确认)
关键标志位 SYN(同步)、ACK(确认) FIN(结束)、ACK(确认)
主动方状态流 CLOSED → SYN_SENT → ESTABLISHED ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
被动方状态流 CLOSED → LISTEN → SYN_RCVD → ESTABLISHED ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
资源占用 建立后占用socket、缓冲区等资源 关闭过程中逐步释放资源(TIME_WAIT阶段仍占用少量资源)

五、总结:TCP连接管理的核心逻辑

无论是三次握手还是四次挥手,TCP的设计始终围绕"可靠 "和"高效"两个关键词:

  • 可靠:通过双向确认(握手)、状态监控(TIME_WAIT)、重发机制(丢失ACK重发),确保连接建立和关闭的安全性;
  • 高效:通过合并报文(三次握手中的SYN+ACK)、状态流转(避免资源浪费),减少网络交互次数,提升传输效率。

希望通过本文的类比和拆解,你能彻底搞懂TCP三次握手与四次挥手------下次再遇到相关问题,不妨想想"打电话"的场景,很多复杂的技术细节都会变得通俗易懂!

相关推荐
qq_310658515 小时前
webrtc代码走读(八)-QOS-FEC-flexfec rfc8627
网络·c++·webrtc
mohesashou5 小时前
HCIP第二次作业(VRRP/STP/VLAN/Eth-trunk/NAT)
网络
讲师-汪春波7 小时前
[运维]宝塔 Apache环境使用CDN获取访客真实IP方法
运维·tcp/ip·apache·cdn
h79971010 小时前
wsl使用代理网络
网络
ghie909012 小时前
Reactor 模式结合 epoll
网络
m0_7381207212 小时前
网络安全编程——TCP客户端以及服务端Python实现
python·tcp/ip·安全·web安全·网络安全
无聊的小坏坏13 小时前
从零开始:C++ TCP 服务器实战教程
服务器·c++·tcp/ip
qq_3106585114 小时前
webrtc代码走读(六)-QOS-FEC冗余度配置
网络·c++·webrtc
飞飞是甜咖啡14 小时前
网络渗流:爆炸渗流
网络