ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

【大白话说Java面试题 第214题】【10_网络协议篇】第5题:说一下 TCP 协议的三次握手和四次挥手

【大白话说Java面试题 第214题】【10_网络协议篇】第5题:说一下 TCP 协议的三次握手和四次挥手 PDF大白话说Java面试题 — 10_网络协议篇第5题说一下 TCP 协议的三次握手和四次挥手回答核心考点 TCP 三次握手和四次挥手是网络面试的必考题大厂面试官不会满足于流程背诵而是深入考察状态转换图11 种状态的完整迁移路径、半连接队列与全连接队列SYN Queue / Accept Queue 的容量与溢出处理、为什么不是两次/四次历史连接、ISN 同步、资源浪费的三层分析、四次挥手的 ACK 和 FIN 为什么通常分开发全双工关闭语义、TIME_WAIT 的 2MSL 精确计算、以及CLOSE_WAIT 堆积的排查与根因。面试官真正想判断的是你是否能从协议设计原理和工程实践两个维度给出有深度的分析。1. TCP 状态机全景图TCP 连接生命周期涉及11 种状态理解状态迁移是排查网络问题的核心能力-------- 主动打开 | CLOSED | 被动打开 ---------| |----------- | -------- | | | | | | 发送SYN | | 监听 | | v v | | ------------ | | | LISTEN | | | ------------ | | | | | | 收到SYN | | v | | ------------ | ------| SYN_SENT | | | ------------ | | | | | 收到SYNACK | 收到SYN | | | 发送SYNACK | | v v | ------------ ------------ -----| ESTABLISHED|----| SYN_RCVD | ------------ ------------ | 数据传输 | | | 主动关闭 | | 被动关闭 ---------- ---------- | | | v v v ------------ ------------ ------------ | FIN_WAIT_1 | | CLOSE_WAIT | | LAST_ACK | ------------ ------------ ------------ | | | 收到ACK | 收到FIN | 收到ACK | | | | v v v ------------ ------------ ------------ | FIN_WAIT_2 | | CLOSED | | CLOSED | ------------ ------------ ------------ | 收到FIN | v ------------ | TIME_WAIT | -- 等待 2MSL ------------ | v ------------ | CLOSED | ------------关键状态说明状态含义典型问题SYN_SENT客户端发送 SYN 后等待 SYNACK连接超时服务端未响应SYN_RCVD服务端收到 SYN 后等待 ACKSYN Flood 攻击时大量堆积ESTABLISHED连接建立可传输数据正常通信状态FIN_WAIT_1主动关闭方发送 FIN 后等待 ACK对端未响应 FINFIN_WAIT_2收到 ACK 后等待对端 FIN对端未关闭连接长时间停留CLOSE_WAIT被动关闭方收到 FIN 后等待应用 close()应用层 Bug 导致堆积LAST_ACK被动关闭方发送 FIN 后等待 ACK正常过渡状态TIME_WAIT主动关闭方等待 2MSL大量堆积耗尽端口CLOSING双方同时关闭罕见同时发送 FIN2. 三次握手建立连接2.1 完整流程与状态转换步骤方向报文内容发送方状态接收方状态核心确认第一次C → SSYN1, seqxISN_CCLOSED→SYN_SENTLISTEN客户端告知服务端自己的初始序列号第二次S → CSYN1, ACK1, seqyISN_S,ackx1SYN_SENTLISTEN→SYN_RCVD服务端确认收到 SYN并告知自己的 ISN第三次C → SACK1, seqx1, acky1SYN_SENT→ESTABLISHEDSYN_RCVD→ESTABLISHED客户端确认收到 SYNACK服务端确认闭环完成第三次握手可以携带数据吗可以。RFC 9293 允许第三次握手的 ACK 携带应用数据但接收端在确认连接有效前不能交付给应用。如果第三次 ACK 丢失但随后发送的携带数据且带 ACK 标志的报文到达服务端可将其视为有效的第三次握手确认。2.2 为什么是三次握手三层分析原因一防止历史连接初始化首要原因客户端发送 SYN1seq90后因网络延迟滞留超时后重发 SYN2seq100并成功建连、传输、释放。此时延迟的 SYN1 到达服务端两次握手服务端收到 SYN1 后直接建连分配资源但客户端已无此连接状态导致服务端维护无效连接三次握手服务端回复 SYNACK 后等待最终 ACK客户端发现 ack91 而非期望的 101发送 RST 终止连接服务端释放资源。原因二同步双方初始序列号ISNTCP 依赖序列号保证可靠传输去重、排序、确认。双方必须互相确认对方的 ISN客户端发送 ISN_C需要服务端 ACK 确认服务端发送 ISN_S需要客户端 ACK 确认。两次握手只能保证一方的 ISN 被确认无法保证双向同步。四次握手可以但第二步和第三步可合并为一步SYNACK因此三次是最小可靠次数。原因三避免资源浪费两次握手下服务端每收到一个 SYN 就必须建连无法区分是有效请求还是历史重发。网络拥堵时客户端重复发送 SYN服务端会建立多个冗余无效连接造成资源浪费。三次握手通过最终 ACK 确认闭环服务端只在确认有效后才分配资源。握手次数能否防止历史连接能否同步双方 ISN资源浪费风险结论两次❌ 不能❌ 只能单向⚠️ 高不可用三次✅ 能✅ 双向✅ 低最优四次✅ 能✅ 双向✅ 低冗余第三步可合并2.3 半连接队列与全连接队列服务端在握手过程中维护两个队列是排查连接建立慢、SYN Flood 攻击的关键队列保存状态触发条件溢出后果半连接队列SYN QueueSYN_RCVD状态的连接收到 SYN回复 SYNACK 后SYN Flood 攻击时满新连接无法建立全连接队列Accept QueueESTABLISHED状态的连接收到 ACK三次握手完成应用accept()不及时时满客户端认为连接成功但无法通信内核参数调优net.ipv4.tcp_max_syn_backlog半连接队列长度net.core.somaxconn全连接队列长度受listen()的backlog参数限制取两者较小值net.ipv4.tcp_syncookiesSYN 队列满时启用 Cookie 机制不分配资源验证客户端合法性。3. 四次挥手断开连接3.1 完整流程与状态转换TCP 是全双工通信两个方向的数据传输需要分别关闭、分别确认。步骤方向报文内容发送方状态接收方状态核心语义第一次A → BFIN1, sequESTABLISHED→FIN_WAIT_1ESTABLISHEDA 不再发送数据但可继续接收第二次B → AACK1, acku1FIN_WAIT_1ESTABLISHED→CLOSE_WAITB 确认收到 A 的关闭请求第三次B → AFIN1, seqvFIN_WAIT_2收到ACK后CLOSE_WAIT→LAST_ACKB 也不再发送数据第四次A → BACK1, ackv1FIN_WAIT_2→TIME_WAITLAST_ACK→CLOSEDA 最终确认等待 2MSL 后关闭3.2 为什么是四次挥手因为 TCP 是全双工的A 发 FIN 只表示我不再发送数据了不代表 B 也立刻没有数据要发。B 收到 FIN 后内核自动回 ACK 确认第二次挥手立即响应应用层可能还有数据未发送需等待处理完并调用close()后才发 FIN第三次挥手。回 ACK和发 FIN的触发时机解耦通常无法合并因此需要四次。3.3 什么情况下可以三次挥手当 B 收到 FIN 时恰好没有待发数据且应用层立即调用close()同时延迟确认Delayed ACK机制允许 ACK 等待合并时第二次的 ACK 和第三次的 FIN 可合并为一个FINACK报文抓包上呈现三次交互。正常四次挥手 优化三次挥手 A → B: FIN A → B: FIN B → A: ACK B → A: FINACK合并 B → A: FIN A → B: ACK A → B: ACK3.4 TIME_WAIT 状态的深度解析为什么需要 2MSL确保最后一个 ACK 到达若 ACK 丢失被动关闭方会重传 FIN主动方需能在TIME_WAIT期间收到并重发 ACK防止旧连接报文干扰新连接等待 2MSL 确保网络中所有旧连接的报文全部消亡避免新连接可能复用相同四元组收到旧报文导致数据混乱。为什么是 2MSL 而不是 1MSL因为最坏情况下最后一个 ACK 从 A 到 B 需要 1MSLB 重传的 FIN 从 B 到 A 又需要 1MSL总共 2MSL 才能覆盖这个往返周期。生产隐患与解决方案问题根因解决方案大量TIME_WAIT耗尽端口高并发短连接HTTP/1.0开启tcp_tw_reusetcp_timestamps改用长连接/连接池TIME_WAIT导致端口复用失败四元组源IP、源端口、目的IP、目的端口唯一标识连接多源IP绑定、扩大 ephemeral 端口范围注意tcp_tw_reuse只能复用TIME_WAIT端口用于出站连接作为客户端不能用于服务端监听端口。服务端应通过长连接和连接池解决。4. CLOSE_WAIT 堆积应用层 Bug 的照妖镜CLOSE_WAIT是被动关闭方收到 FIN 后的状态表示我已收到你的关闭请求但我还有数据要发/我还没 close()。如果应用层迟迟不调用close()连接将永久停留在CLOSE_WAIT耗尽文件描述符。排查命令ss-tan|grepCLOSE_WAIT|wc-l# 或netstat-tan|grepCLOSE_WAIT根因分析应用层未关闭 Socket代码中InputStream.read()返回 -1 后未调用socket.close()线程池阻塞处理请求的线程被阻塞如数据库查询慢无法及时释放连接连接池配置不当连接池最大连接数过小新请求排队等待旧连接无法释放。解决方案确保在finally块中关闭 Socket使用 try-with-resources 自动关闭监控线程池活跃线程数设置合理的超时时间。5. 生产环境避坑指南5.1 SYN Flood 攻击防护攻击者发送大量伪造源 IP 的 SYN 报文占满半连接队列导致正常连接无法建立。防护手段配置原理SYN Cookiesnet.ipv4.tcp_syncookies 1SYN 队列满时用 Cookie 机制验证客户端合法性不分配资源增大半连接队列tcp_max_syn_backlog 65535提高容量缩短 SYN 超时tcp_synack_retries 2减少半连接占用时间云厂商 DDoS 防护-流量清洗过滤恶意 SYN5.2 连接建立慢排查现象可能原因排查手段连接超时服务端未响应 SYNtcpdump抓包检查防火墙/安全组连接成功但无法通信全连接队列溢出ss -lnt查看Recv-Q是否超过Send-Q偶发超时半连接队列溢出查看SYNs to LISTEN sockets dropped计数5.3 内核参数调优速查表参数默认值建议值作用tcp_max_syn_backlog12865535半连接队列长度somaxconn12865535全连接队列长度tcp_syncookies01SYN Flood 防护tcp_tw_reuse01复用 TIME_WAIT 端口出站tcp_timestamps11tcp_tw_reuse 前置条件tcp_fin_timeout6030缩短 FIN_WAIT_2 超时6. 面试官追问与高分回答模板追问 1“画一下 TCP 三次握手的状态转换图”低分回答“客户端发 SYN服务端回 SYNACK客户端再发 ACK。”没有状态转换高分回答三次握手涉及 5 个状态转换客户端从CLOSED发送 SYN 后进入SYN_SENT服务端从LISTEN收到 SYN 后进入SYN_RCVD回复 SYNACK客户端收到 SYNACK 后进入ESTABLISHED发送 ACK服务端收到 ACK 后从SYN_RCVD进入ESTABLISHED。关键点SYN_RCVD是服务端的中间状态用于等待最终 ACK。如果没有这个中间状态两次握手服务端无法区分有效 SYN 和历史重发会直接建连分配资源造成浪费。追问 2“为什么是三次握手不是两次”低分回答“为了防止重复连接。”太笼统高分回答核心原因有三层防止历史连接初始化首要若客户端 SYN 因延迟滞留超时重发后成功建连并释放旧 SYN 到达服务端。两次握手下服务端直接建连但客户端已无此状态导致服务端维护无效连接。三次握手通过最终 ACK 确认闭环客户端会 RST 这个失效请求。同步双方 ISNTCP 依赖序列号保证可靠传输双方必须互相确认对方的 ISN。两次握手只能保证一方的 ISN 被确认。避免资源浪费两次握手下服务端每收到一个 SYN 就必须建连无法区分有效请求和历史重发网络拥堵时会产生大量冗余连接。追问 3“四次挥手为什么不是三次什么情况下可以是三次”低分回答“因为 TCP 是全双工的。”没有解释清楚高分回答“TCP 是全双工两个方向需分别关闭。被动关闭方收到 FIN 后内核自动回 ACK第二次但应用层可能还有数据未发送需等待close()后才发 FIN第三次。回 ACK’和’发 FIN’触发时机解耦通常无法合并所以是四次。三次挥手的条件是被动关闭方收到 FIN 时恰好无待发数据应用层立即close()且延迟 ACK 允许合并时ACK 和 FIN 可合并为FINACK呈现三次交互。”追问 4“TIME_WAIT 状态的作用是什么大量 TIME_WAIT 怎么解决”低分回答“等待 2MSL防止报文干扰。”没有提解决方案高分回答TIME_WAIT 等待 2MSL 有两个作用确保最后一个 ACK 到达若 ACK 丢失被动方重传 FIN主动方需能重发 ACK防止旧连接报文干扰新连接等待网络中旧报文全部消亡。大量 TIME_WAIT 的解决方案开启tcp_tw_reusetcp_timestamps仅出站连接改用长连接HTTP Keep-Alive减少短连接数量使用连接池多源 IP 绑定扩大可用端口范围。追问 5“服务端出现大量 CLOSE_WAIT怎么排查”低分回答“应用层没关闭连接。”没有排查手段高分回答CLOSE_WAIT是被动关闭方收到 FIN 后等待应用close()的状态。大量堆积说明应用层未及时释放连接。排查步骤ss -tan | grep CLOSE_WAIT | wc -l确认数量检查应用代码是否在read()返回 -1 后调用了close()检查线程池是否有线程被阻塞如慢 SQL导致无法及时处理连接释放检查连接池配置最大连接数是否过小。根因通常是应用层 Bug未关闭 Socket或业务逻辑阻塞。追问 6“三次握手过程中如果第三次 ACK 丢了会怎样”高分回答第三次 ACK 丢失后服务端仍处于SYN_RCVD状态启动重传定时器超时后重传 SYNACK默认重试 5 次间隔指数退避客户端已认为连接建立ESTABLISHED可能开始发送数据。如果数据报文到达服务端服务端发现不是期望的 ACK可能丢弃或回复 RST如果客户端发送的数据报文中带有 ACK 标志且确认号正确服务端可将其视为有效的第三次握手直接建立连接并接收数据。所以第三次 ACK 丢失不一定会导致连接失败客户端的数据报文可能’救场’。7. 方案选型速查表问题场景排查命令/参数解决方案连接建立慢/超时tcpdumpss -lnt检查防火墙、调整tcp_max_syn_backlogSYN Flood 攻击netstat -sgrep SYNs大量 TIME_WAITss -tangrep TIME_WAIT大量 CLOSE_WAITss -tangrep CLOSE_WAIT全连接队列溢出ss -lnt看Recv-Q增大somaxconn 应用及时accept()半连接队列溢出netstat -s看 dropped增大tcp_max_syn_backlogtcp_syncookies面试官想要的满分总结TCP 三次握手和四次挥手的本质不是发了几个包而是状态机的精确状态转换和全双工通信的优雅管理。三次握手的核心目的通过SYN_RCVD中间状态防止历史连接初始化同步双方 ISN避免资源浪费。服务端维护的半连接队列SYN Queue和全连接队列Accept Queue是排查连接建立问题的关键抓手。四次挥手的核心原因TCP 全双工两个方向需分别关闭。被动关闭方的 ACK 和 FIN 通常分开发因为 ACK 是内核自动响应FIN 需等待应用层close()。只有在无待发数据 延迟 ACK 合并时才可能呈现三次挥手。TIME_WAIT的 2MSL 不是多余等待而是确保 ACK 到达和旧报文消亡的必要机制。高并发短连接场景下需通过tcp_tw_reuse 长连接缓解。CLOSE_WAIT则是应用层 Bug 的照妖镜大量堆积时优先排查代码是否及时close()。最后记住面试中画出完整的状态转换图比背诵流程更有说服力。理解每个状态的存在意义才能真正掌握 TCP 的连接管理。觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~
返回列表