2026/4/18 8:50:19
网站建设
项目流程
昆山网站建设网站,妹妹强迫我和她做网站,新媒体运营工资一般多少,集团网站建设服务平台视频看了几百小时还迷糊#xff1f;关注我#xff0c;几分钟让你秒懂#xff01;在开发 Spring Boot 应用时#xff0c;你是否遇到过这些问题#xff1a;为什么服务刚启动就收到大量连接请求#xff1f;为什么高并发下出现 TIME_WAIT 占满端口#xff1f;面试官问#…视频看了几百小时还迷糊关注我几分钟让你秒懂在开发 Spring Boot 应用时你是否遇到过这些问题为什么服务刚启动就收到大量连接请求为什么高并发下出现TIME_WAIT占满端口面试官问“TCP 建立连接为什么是三次不是两次或四次”这些问题的背后都藏着一个关键知识点TCP 的三次握手与四次挥手。今天我们就用生活化比喻 Java 代码演示 反例分析彻底搞懂这个网络核心机制 一、为什么需要“握手”和“挥手”想象你打电话给朋友拨号 → 对方接听 → 你说“喂听得见吗” → 对方回“听得见”→ 这才确认双方都能说话建立连接。聊完后你说“挂了啊” → 对方说“好” → 你挂电话 → 对方也挂→ 确保双方都同意结束断开连接。TCP 就是这样一种“严谨的通信协议”它通过三次握手建立连接四次挥手断开连接确保数据传输的可靠性。 二、三次握手Three-Way Handshake—— 建立连接✅ 正确流程客户端 → 服务端步骤发送方动作标志位1客户端发送 SYNSYN1, seqx2服务端回复 SYNACKSYN1, ACK1, seqy, ackx13客户端发送 ACKACK1, seqx1, acky1✅ 此时连接建立成功双方可开始传输数据。 为什么必须是三次两次行不行反例如果只有两次握手客户端发送 SYN服务端收到后直接认为连接建立开始发数据但客户端可能根本没收到 SYN-ACK网络丢包结果服务端一直在发数据客户端却不知道连接存在 →资源浪费 数据丢失。 三次握手的核心目的让双方都确认对方的发送和接收能力正常。 三、四次挥手Four-Way Wavehand—— 断开连接TCP 是全双工的意味着 A→B 和 B→A 可以同时传数据。所以断开时每个方向都要单独关闭。✅ 正确流程步骤发送方动作状态变化1客户端发送 FIN进入FIN_WAIT_12服务端回复 ACK进入CLOSE_WAIT3服务端发送 FIN等应用层处理完进入LAST_ACK4客户端回复 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中看到ESTABLISHED、TIME_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客户端端口多调整内核参数Linuxnet.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 --SYNACK-- Server Client --ACK-- Server → 连接建立 四次挥手断连 Client --FIN-- Server Client --ACK-- Server Client --FIN-- Server Client --ACK-- Server → 连接关闭Client 进入 TIME_WAIT 记住口诀“三次握手防失效四次挥手因双工”视频看了几百小时还迷糊关注我几分钟让你秒懂