面试官问:TCP三次握手与四次挥手有什么区别?一张图+电话接通挂断比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)
面试官问:TCP三次握手与四次挥手有什么区别?一张图+电话接通挂断比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)
📌 你是不是也这样:知道TCP有三次握手和四次挥手,但面试官一追问“为什么握手是三次而不是两次”“为什么挥手是四次而不是三次”“TIME_WAIT有什么用”就答不上来了?
今天一张图 + 一个电话接通挂断故事 + 状态变迁详解 + 六道追问,彻底拿下这道题。
📝摘要:TCP是面向连接的可靠传输协议,通过三次握手建立连接(确保双方收发能力正常),通过四次挥手释放连接(因TCP全双工特性,需分别关闭两个方向的通道)。本文用“打电话”比喻 + 状态变迁图 + 高频追问(为什么是3次/4次、SYN洪水、TIME_WAIT作用等),彻底讲透这道网络面试必考题。一句话:三次握手建立连接,四次挥手释放连接;握手少一次不安全,挥手多一次因半关闭。
我是折哥,《Java 85题图解版》系列连载中(已更新44题,建议收藏本系列)。
每周2-3篇,85题通关路线一键追完。
👉点击关注,第一时间收到每篇新题推送。
- 上一篇:面试官问:单例模式的7种写法与JVM层面分析?
- 下一篇预告:面试官问:HTTP和HTTPS有什么区别?(待发布)
- 全部85题:点击查看总目录(关注专栏,追更不迷路)
一句话总结:三次握手建立连接,四次挥手释放连接;握手少一次不安全,挥手多一次因半关闭。
三次握手:Client → Server(SYN)→ Client(SYN+ACK)→ Server(ACK)→ 连接建立 → 像打电话:A说“喂”(SYN),B回“听到了,你能听到我吗”(SYN+ACK),A回“听到了”(ACK),开始通话。
四次挥手:Client → Server(FIN)→ Server(ACK)→ Server(FIN)→ Client(ACK)→ 连接释放 → 像挂电话:A说“我说完了”(FIN),B回“知道了,等我一下”(ACK),B说完后说“我也说完了”(FIN),A回“好的,挂了”(ACK),通话结束。
背诵口诀:三次握手建连接,四次挥手断连接;握手确认收发能力,挥手半关各自断。
核心设计理念:TCP是全双工协议——双方可以同时收发数据,因此连接建立需要双向确认,连接释放需要双方各自关闭。
💬 面试还原
面试官:TCP为什么是三次握手?为什么是四次挥手?它们有什么区别?
这是网络面试中必问必考的核心题,直接进入正题。
🧠 一图看懂:TCP三次握手与四次挥手全貌
🍵 生活比喻:打电话
三次握手 = 接通电话
你想给朋友打电话(建立TCP连接):
- 第一次握手(SYN):你拿起电话说“喂?”(客户端发送SYN,请求建立连接)
- 第二次握手(SYN+ACK):朋友听到后回复“听到了,你能听到我吗?”(服务端回复SYN+ACK,确认收到并询问对方)
- 第三次握手(ACK):你回答“能听到,我们开始说吧”(客户端回复ACK,连接建立)
为什么不是两次?如果只到第二步,你确认了朋友能听到你,但朋友还不知道你能不能听到他——第三次握手就是为了让朋友确认“你能听到他”。两次握手无法确认双方的收发能力都正常。
四次挥手 = 挂断电话
通话结束,准备挂断(释放TCP连接):
- 第一次挥手(FIN):你说“我说完了,先不说了”(客户端发送FIN,请求关闭发送通道)
- 第二次挥手(ACK):朋友说“好的,我知道了,等我一下”(服务端回复ACK,客户端→服务端方向关闭)
- 第三次挥手(FIN):朋友把手头的话说完后说“我也说完了”(服务端发送FIN,关闭服务端→客户端方向)
- 第四次挥手(ACK):你最后确认“好的,挂了”(客户端回复ACK,连接彻底释放)
为什么不是三次?第二次和第三次不能合并——因为朋友说“知道了”是内核自动回复的(很快),但朋友可能还有话没说完,什么时候说“我也说完了”由他自己决定(可能很久)。所以这两步必须分开。
📊 核心对比表(面试速查版)
三次握手 vs 四次挥手
| 维度 | 三次握手(建立连接) | 四次挥手(释放连接) |
|---|---|---|
| 目的 | 确认双方收发能力正常 | 优雅关闭双向通道,确保数据完整传输 |
| 报文数 | 3个 | 4个 |
| 标志位 | SYN → SYN+ACK → ACK | FIN → ACK → FIN → ACK |
| 能否合并 | 第二次和第三次可以合并(三次的原因) | 第二次和第三次不能合并(四次的原因) |
| 原因 | 建立连接不需要等待应用层参与 | ACK由内核回复,FIN由应用层控制,无法合并 |
| 状态变迁 | CLOSED→SYN_SENT→ESTABLISHED | ESTABLISHED→FIN_WAIT_1→CLOSE_WAIT→FIN_WAIT_2→LAST_ACK→TIME_WAIT→CLOSED |
| 全双工 | 建立双向通道 | 分别关闭两个方向的通道 |
关键状态说明
| 状态 | 含义 | 出现阶段 |
|---|---|---|
| SYN_SENT | 客户端已发送SYN,等待服务端确认 | 第一次握手后 |
| SYN_RCVD | 服务端已收到SYN,已回复SYN+ACK | 第二次握手后 |
| ESTABLISHED | 连接已建立,可以传输数据 | 第三次握手后 |
| FIN_WAIT_1 | 客户端已发送FIN,等待ACK | 第一次挥手后 |
| CLOSE_WAIT | 服务端收到FIN,等待应用层关闭 | 第二次挥手后 |
| FIN_WAIT_2 | 客户端收到ACK,等待服务端FIN | 第二次挥手后 |
| LAST_ACK | 服务端已发送FIN,等待客户端ACK | 第三次挥手后 |
| TIME_WAIT | 客户端等待2MSL后关闭 | 第四次挥手后 |
| 2MSL | 报文最大生存时间的2倍,确保最后一个ACK到达 | TIME_WAIT状态 |
🔍 高频面试追问(6道大厂真题)
追问1:为什么TCP是三次握手,不是两次或四次?
回答要点:三次正好:①确认双方收发能力②防止历史连接③效率最优。
详细回答:
不是两次的原因:两次握手只能证明客户端能发、服务端能收,但无法证明服务端能发、客户端能收。TCP是全双工协议,需要双向确认。如果只有两次握手,服务端发出确认后连接就建立了,但此时服务端并不确定客户端是否收到了自己的确认,也不知道客户端是否准备好接收数据。
不是四次的原因:第三次和第二次可以合并——服务端在回复SYN+ACK时,可以同时确认客户端的SYN并发送自己的SYN,不需要分两次。三次握手已经足以确认双方的收发能力,多一次就是浪费。
还有一个重要原因:防止已失效的连接请求报文段突然又传到服务端(历史连接问题)。三次握手可以避免服务端在客户端毫不知情的情况下建立无效连接。
追问2:为什么挥手是四次,不能像握手一样合并成三次?
回答要点:ACK和FIN的触发时机不同——ACK由内核立即回复,FIN由应用层决定何时发送。
详细回答:
第二次挥手(ACK)是服务端收到FIN后内核自动回复的,速度很快。第三次挥手(FIN)是服务端应用层调用close()触发的,要等应用层处理完剩余数据才能发送。
这两步的触发时机完全不同,无法合并。如果合并成三次,就意味着服务端在收到FIN时必须立即关闭自己的发送通道,但此时它可能还有数据没发完。四次挥手的设计正是为了确保所有数据都能完整传输。
追问3:TIME_WAIT状态是什么?为什么需要2MSL?
回答要点:TIME_WAIT = 等待2MSL后关闭,目的是①保证最后的ACK到达②让旧报文在网络中消失。
详细回答:
主动关闭方(通常是客户端)在发送最后一个ACK后会进入TIME_WAIT状态,等待2MSL(Maximum Segment Lifetime,报文最大生存时间)后才真正关闭。
两个核心目的:
- 保证最后的ACK能到达:如果服务端没收到最后一个ACK(第四次挥手),会重发FIN。客户端在TIME_WAIT状态下可以重发ACK,确保服务端正常关闭。
- 让旧报文在网络中消失:避免本次连接中延迟到达的报文干扰使用相同四元组(源IP、源端口、目标IP、目标端口)的下一个连接。
如果TIME_WAIT过多,会占用端口资源,可能导致无法创建新连接。
追问4:什么是SYN洪水攻击?如何防范?
回答要点:攻击者发送大量SYN但不完成第三次握手,耗尽服务端资源。
详细回答:
SYN洪水攻击:攻击者向服务端发送大量SYN报文(第一次握手),但收到服务端的SYN+ACK后不回复ACK(不完成第三次握手),导致服务端一直处于SYN_RCVD状态,半连接队列被占满,无法处理正常请求。
防范措施:
- SYN Cookie:服务端收到SYN后不立即分配资源,而是根据SYN计算一个Cookie作为初始序列号回复,收到ACK后再验证Cookie真实性。
- 限制半连接数量:设置合理的半连接队列上限。
- 缩短超时时间:减少等待ACK的时间,快速释放半开连接占用的资源。
追问5:TCP和UDP有什么区别?
回答要点:TCP面向连接、可靠、有序、慢;UDP无连接、不可靠、无序、快。
详细回答:
维度 TCP UDP 连接 面向连接(三次握手) 无连接 可靠性 可靠传输(确认重传) 不可靠,不保证到达 有序性 保证按序到达 不保证顺序 速度 慢(开销大) 快(开销小) 应用场景 HTTP、FTP、SMTP DNS、视频直播、语音通话
追问6:三次握手中可以携带数据吗?
回答要点:第三次可以携带数据,前两次不行。
详细回答:
TCP规定第三次握手(ACK)可以携带数据,因为此时客户端已经确认了服务端的收发能力,连接已基本建立。
但第一次和第二次握手不能携带数据——因为此时连接还未完全建立,双方还未确认对方的收发能力,贸然发送数据无法保证可靠传输。
💣 避坑指南
| 序号 | 错误认知 | 正确理解 | 后果 |
|---|---|---|---|
| 1 | “握手和挥手只是名字不同,本质一样” | 握手3次,挥手4次,原因完全不同 | 面试答不出“为什么” |
| 2 | “三次握手和四次挥手都是为了确认” | 握手确认收发能力,挥手确保数据完整 | 混淆建立和释放的目的 |
| 3 | “挥手少一次不行吗?” | 不行,ACK和FIN不能合并 | 会中断数据传输,丢失数据 |
| 4 | “TIME_WAIT是浪费,应该尽快关闭” | TIME_WAIT是必要的,保证可靠关闭 | 可能导致数据丢失或连接混乱 |
| 5 | “只有客户端可以主动关闭连接” | 客户端和服务端都可以主动关闭 | 误解协议设计 |
💻 可运行验证代码
importjava.io.*;importjava.net.*;publicclassTCPDemo{// 模拟TCP三次握手和四次挥手(通过Socket连接和关闭演示)publicstaticvoidmain(String[]args)throwsInterruptedException{// 服务端(模拟)ThreadserverThread=newThread(()->{try(ServerSocketserverSocket=newServerSocket(8888)){System.out.println("[服务端] LISTEN状态 - 等待客户端连接");Socketsocket=serverSocket.accept();// 三次握手在此完成System.out.println("[服务端] ESTABLISHED状态 - 连接已建立");// 接收数据BufferedReaderreader=newBufferedReader(newInputStreamReader(socket.getInputStream()));Stringmsg=reader.readLine();System.out.println("[服务端] 收到消息: "+msg);// 四次挥手在socket.close()时自动完成Thread.sleep(2000);socket.close();System.out.println("[服务端] CLOSED状态 - 连接已关闭");}catch(Exceptione){e.printStackTrace();}});// 客户端(模拟)ThreadclientThread=newThread(()->{try{Thread.sleep(500);Socketsocket=newSocket("localhost",8888);// 触发三次握手System.out.println("[客户端] ESTABLISHED状态 - 连接已建立");// 发送数据PrintWriterwriter=newPrintWriter(socket.getOutputStream());writer.println("Hello TCP!");writer.flush();Thread.sleep(3000);socket.close();// 触发四次挥手System.out.println("[客户端] CLOSED状态 - 连接已关闭");}catch(Exceptione){e.printStackTrace();}});serverThread.start();clientThread.start();serverThread.join();clientThread.join();System.out.println("=== TCP三次握手和四次挥手演示完成 ===");System.out.println("三次握手: socket.accept() 和 new Socket() 之间完成");System.out.println("四次挥手: socket.close() 时自动完成");}}验证命令(查看TCP连接状态):
# Linux/Mac查看TCP连接状态netstat-ant|grep8888# 或ss-ant|grep8888# Windowsnetstat-an|findstr8888❓ 评论区挑战
问题:以下关于TCP三次握手和四次挥手的说法,哪一个是错误的?
// TCP连接建立与释放// 三次握手 → 数据传输 → 四次挥手A. 三次握手的目的是确认双方的收发能力都正常
B. 四次挥手是因为TCP是全双工协议,需要分别关闭两个方向的通道
C. 四次挥手中的第二次(ACK)和第三次(FIN)可以合并为一次
D. TIME_WAIT状态是为了确保最后一个ACK能到达对方
💬 欢迎在评论区写出你的答案和理由,我会在下一篇文章发布后更新本文,公布答案及错误选项逐项解析。
✅ 答案公布
正确答案:C. 四次挥手中的第二次(ACK)和第三次(FIN)可以合并为一次
解析:
- 第二次ACK由内核收到FIN后立即自动回复,第三次FIN由应用层决定何时发送(等数据发完)。
- 两者触发时机不同,无法合并。如果强行合并,就意味着服务端必须在收到FIN时立即关闭发送通道,而此时可能还有数据未发送完。
- 选项A正确:三次握手确认双方收发能力。
- 选项B正确:TCP全双工,挥手需要关闭两个方向。
- 选项D正确:TIME_WAIT保证最后的ACK到达。
📌 总结
| 维度 | 三次握手(建立) | 四次挥手(释放) |
|---|---|---|
| 报文数 | 3个 | 4个 |
| 核心目的 | 确认收发能力 | 确保数据完整传输 |
| 标志位 | SYN → SYN+ACK → ACK | FIN → ACK → FIN → ACK |
| 能否合并 | ✅ 可以(三次的原因) | ❌ 不能(四次的原因) |
| 最终状态 | ESTABLISHED | CLOSED(主动方经历TIME_WAIT) |
面试官最看重的三个点:
- 握手为什么是三次:确认双向收发能力 + 防止历史连接
- 挥手为什么是四次:TCP全双工 + ACK和FIN触发时机不同
- TIME_WAIT的作用:保证最后一个ACK到达 + 让旧报文消失
📚 系列导航
- 上一篇:面试官问:单例模式的7种写法与JVM层面分析?
- 下一篇预告:面试官问:HTTP和HTTPS有什么区别?(待发布)
- 全部85题:点击查看总目录(关注专栏,每周2-3篇,一键追更)
📘搭配学习效果更佳
本篇图解帮你快速建立知识画面记忆,如果想深入理解TCP/IP协议栈的完整工作原理,可以配合姊妹系列《Java 100天进阶之路》对应章节一起学:
从零基础到上岗就业,108篇完整学习地图,每篇标配生活类比 + 可运行代码 + 避坑表 + 面试高频题 + 练习题,不背八股文,真正讲透“为什么”。
👉 《Java 100天进阶之路》完整目录导航
学习建议:图解系列负责“快速建立知识图谱”,进阶系列负责“深入理解原理”,两个系列搭配使用,面试备考效率翻倍。
💬你面试时被问过TCP三次握手和四次挥手吗?面试官追问到了什么深度?欢迎评论区分享你的面试经历~
