news 2026/5/13 20:08:53

一文给你讲清楚什么是三次握手、四次挥手!小白也能秒懂

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文给你讲清楚什么是三次握手、四次挥手!小白也能秒懂

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

在开发 Spring Boot 应用时,你是否遇到过这些问题:

  • 为什么服务刚启动就收到大量连接请求?
  • 为什么高并发下出现TIME_WAIT占满端口?
  • 面试官问:“TCP 建立连接为什么是三次,不是两次或四次?”

这些问题的背后,都藏着一个关键知识点:TCP 的三次握手与四次挥手

今天,我们就用生活化比喻 + Java 代码演示 + 反例分析,彻底搞懂这个网络核心机制!


🧩 一、为什么需要“握手”和“挥手”?

想象你打电话给朋友:

  • 拨号 → 对方接听 → 你说“喂,听得见吗?” → 对方回“听得见!”
    → 这才确认双方都能说话(建立连接)。

  • 聊完后,你说“挂了啊” → 对方说“好” → 你挂电话 → 对方也挂
    → 确保双方都同意结束(断开连接)。

TCP 就是这样一种“严谨的通信协议”,它通过三次握手建立连接四次挥手断开连接,确保数据传输的可靠性


🔁 二、三次握手(Three-Way Handshake)—— 建立连接

✅ 正确流程(客户端 → 服务端)

步骤发送方动作标志位
1客户端发送 SYNSYN=1, seq=x
2服务端回复 SYN+ACKSYN=1, ACK=1, seq=y, ack=x+1
3客户端发送 ACKACK=1, seq=x+1, ack=y+1

✅ 此时连接建立成功,双方可开始传输数据。

🎯 为什么必须是三次?两次行不行?

反例:如果只有两次握手

  • 客户端发送 SYN;
  • 服务端收到后直接认为连接建立,开始发数据;
  • 但客户端可能根本没收到 SYN-ACK(网络丢包)
  • 结果:服务端一直在发数据,客户端却不知道连接存在 →资源浪费 + 数据丢失

🔑 三次握手的核心目的:让双方都确认对方的发送和接收能力正常


🚪 三、四次挥手(Four-Way Wavehand)—— 断开连接

TCP 是全双工的,意味着 A→B 和 B→A 可以同时传数据。所以断开时,每个方向都要单独关闭

✅ 正确流程

步骤发送方动作状态变化
1客户端发送 FIN进入FIN_WAIT_1
2服务端回复 ACK进入CLOSE_WAIT
3服务端发送 FIN(等应用层处理完)进入LAST_ACK
4客户端回复 ACK进入TIME_WAIT(等待 2MSL 后关闭)

⚠️ 注意:步骤2和3不能合并!因为服务端可能还有数据要发。

❓ 为什么挥手要四次,而握手只要三次?

  • 握手时,服务端可以把 SYN 和 ACK 合并在一个包里发(因为刚启动,无数据要发);
  • 挥手时,服务端收到 FIN 后,应用层可能还在处理数据,不能立刻发 FIN,必须等业务逻辑完成 → 所以 ACK 和 FIN 要分开。

💻 四、Spring Boot 中如何观察三次握手 & 四次挥手?

虽然 Spring Boot 默认屏蔽了底层细节,但我们可以通过Socket 编程模拟连接过程。

示例:用 Java 写一个简易 TCP 服务端/客户端

服务端(模拟握手/挥手)
// TcpServer.java public class TcpServer { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(8080); System.out.println("服务端启动,等待连接..."); Socket client = server.accept(); // ← 这里完成三次握手! System.out.println("客户端已连接"); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(client.getOutputStream(), true); String msg; while ((msg = in.readLine()) != null) { System.out.println("收到: " + msg); out.println("Echo: " + msg); } // 客户端关闭后,这里会退出循环 client.close(); // ← 触发四次挥手 server.close(); } }
客户端
// TcpClient.java public class TcpClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 8080); // ← 发起三次握手 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out.println("Hello Server!"); System.out.println("收到回复: " + in.readLine()); socket.close(); // ← 发起四次挥手 } }

🔍 运行后,你可以在 Wireshark 或netstat -an | grep 8080中看到ESTABLISHEDTIME_WAIT等状态!


❌ 五、常见反例 & 误区

反例1:服务端未正确关闭连接 → 大量CLOSE_WAIT

// 错误代码:只关输入流,不关 Socket BufferedReader in = new BufferedReader(...); in.close(); // ❌ 这不会触发 FIN! // Socket 一直保持 CLOSE_WAIT,最终耗尽文件描述符!

✅ 正确做法:

socket.close(); // 必须关闭整个 Socket!

反例2:客户端快速重连 →TIME_WAIT占满端口

  • 客户端频繁连接/断开(如压测工具);
  • 每次断开后进入TIME_WAIT(默认 60 秒);
  • 本地端口被占满,无法新建连接。

✅ 解决方案:

  • 服务端主动关闭连接(让服务端进入TIME_WAIT,客户端端口多);
  • 调整内核参数(Linux):
    net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30

⚠️ 六、注意事项

问题说明
SYN Flood 攻击攻击者只发 SYN 不完成握手,耗尽服务端资源 → 需开启 SYN Cookie 防护
2MSL 是什么?TIME_WAIT等待 2 倍最大段生命周期(约 60 秒),防止旧数据包干扰新连接
HTTP 是短连接?HTTP/1.1 默认keep-alive,其实是复用 TCP 连接,避免频繁握手
WebSocket 呢?建立时用 HTTP Upgrade,之后走 TCP 长连接,挥手仍需四次

✅ 七、总结:一张图记住核心

三次握手(建连): Client --SYN--> Server Client <--SYN+ACK-- Server Client --ACK--> Server → 连接建立! 四次挥手(断连): Client --FIN--> Server Client <--ACK-- Server Client <--FIN-- Server Client --ACK--> Server → 连接关闭!(Client 进入 TIME_WAIT)

💡 记住口诀:
“三次握手防失效,四次挥手因双工”


视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 3:09:41

【LangChain】—— History模块使用

【LangChain】—— 使用History实现上下文记忆功能 在对话式AI应用开发中&#xff0c;会话记忆是实现上下文连贯交互的核心能力。LangChain提供了完善的History模块&#xff0c;用于管理会话历史记录&#xff0c;支持临时存储与长期持久化存储两种场景&#xff0c;满足不同业务…

作者头像 李华
网站建设 2026/5/11 3:09:21

‌为什么你的测试总在“环境配置”上浪费时间?

环境配置不是“麻烦”&#xff0c;而是系统性工程失能的表征‌‌测试团队平均每周花费 8–12 小时在环境搭建、修复与协调上&#xff0c;其中 42% 的 CI/CD 流水线瓶颈直接源于环境不一致与配置漂移‌。 这不是“手慢”&#xff0c;而是‌流程未自动化、标准未代码化、责任未闭…

作者头像 李华
网站建设 2026/5/10 3:29:21

用 Java 搞 AI:自主开发 + 生态复用才是长期竞争力

在AI技术深度渗透企业业务的当下&#xff0c;不少Java企业陷入一个误区&#xff1a;认为做AI就得切换到Python生态&#xff0c;要么依赖第三方成品工具&#xff0c;最终陷入“技术断层”或“核心能力外包”的困境。事实上&#xff0c;Java作为支撑80%以上企业级系统的主流语言&…

作者头像 李华
网站建设 2026/5/11 3:08:36

Linux Systemd 停止服务时杀死子进程的机制及 KillMode 参数详解

Systemd 停止服务时杀死子进程的机制 1. Systemd 的进程控制原理 Cgroup 控制组 Systemd 利用 Linux 的 cgroup 机制来管理进程树&#xff1a; # 查看服务的cgroup systemctl show aservice --propertyControlGroup systemd-cgls /system.slice/aservice.service进程树关联…

作者头像 李华