【大白话说Java面试题 第202题】【09_Zookeeper篇】第3题:说一下什么是 TCP 协议?
PDF大白话说Java面试题 — 09_Zookeeper篇第3题说一下什么是 TCP 协议回答核心考点 TCP 是互联网传输层的基石协议大厂面试中不会只问三次握手四次挥手而是深入考察TCP 报文头的每个字段含义序列号、确认号、窗口大小、标志位、滑动窗口与流量控制的数学原理发送窗口/接收窗口/拥塞窗口的动态调整、拥塞控制的四种算法演进慢启动、拥塞避免、快重传、快恢复、以及生产环境的性能调优Nagle 算法、Delayed ACK、TIME_WAIT 优化、TCP Fast Open。核心考察维度包括连接管理、可靠性机制、流量控制、拥塞控制、性能优化、与 UDP 的选型。1. TCP 的核心定位与协议特征TCPTransmission Control Protocol是传输层协议位于 IP 协议之上提供面向连接、可靠传输、字节流、全双工的通信服务。TCP vs UDP 的核心差异特性TCPUDP适用场景连接面向连接三次握手无连接TCPHTTP/HTTPS、FTP、SSHUDPDNS、视频流、游戏可靠性确认、重传、排序不保证TCP文件传输、邮件UDP实时音视频流量控制滑动窗口无TCP防止接收方过载拥塞控制慢启动、拥塞避免无TCP防止网络拥塞头部开销20~60 字节8 字节UDP低延迟场景传输模式字节流数据报TCP无消息边界UDP保留消息边界全双工支持支持双向同时通信TCP 的设计哲学在不可靠的 IP 网络之上通过确认、重传、窗口、拥塞控制机制构建可靠的传输通道。[citation:0]2. TCP 报文结构详解2.1 TCP 头部20~60 字节0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -------------------------------- | Source Port | Destination Port | ← 源/目的端口 (各 2B) -------------------------------- | Sequence Number | ← 序列号 (4B) -------------------------------- | Acknowledgment Number | ← 确认号 (4B) -------------------------------- | Data | |U|A|P|R|S|F| | ← 数据偏移保留标志位 | Offset| Reserved |R|C|S|S|Y|I| Window | ← 窗口大小 (2B) | | |G|K|H|T|N|N| | -------------------------------- | Checksum | Urgent Pointer | ← 校验和紧急指针 -------------------------------- | Options (0~40 bytes) | ← 选项 (可选) -------------------------------- | data | ← 应用数据 --------------------------------关键字段解析字段长度说明Source Port2B源端口标识发送方应用进程Destination Port2B目的端口标识接收方应用进程Sequence Number4B本报文段数据的第一个字节的序列号Acknowledgment Number4B期望收到的下一个字节的序列号ACK1 时有效Data Offset4bit头部长度以 4 字节为单位最小 520 字节最大 1560 字节Flags6bit标志位URG/ACK/PSH/RST/SYN/FINWindow2B接收窗口大小用于流量控制Checksum2B校验和覆盖头部和数据Options0~40B可选字段MSS、窗口扩大、时间戳、SACK 等标志位详解标志名称作用SYNSynchronize同步序列号用于建立连接ACKAcknowledgment确认号有效FINFinish发送方数据发送完毕用于断开连接RSTReset重置连接异常关闭PSHPush立即推送数据到应用层URGUrgent紧急指针有效优先处理[citation:1]3. TCP 连接管理——三次握手与四次挥手3.1 三次握手建立连接客户端 服务器 │ │ │ ─────────── SYN1, seqx ─────────────── │ │ (SYN_SENT) │ (LISTEN) │ │ │ ────── SYN1, ACK1, seqy, ackx1 ─────── │ │ (ESTABLISHED) │ (SYN_RCVD) │ │ │ ─────────── ACK1, seqx1, acky1 ─────── │ │ │ (ESTABLISHED) │ │ 状态流转 客户端: CLOSED → SYN_SENT → ESTABLISHED 服务器: LISTEN → SYN_RCVD → ESTABLISHED为什么是三次不是两次或四次次数问题说明两次无法确认客户端的接收能力服务器发送 SYNACK 后如果客户端不回复 ACK服务器不知道客户端是否收到三次✅ 双方确认收发能力客户端确认我能发SYN、我能收ACK服务器确认我能发SYNACK、我能收ACK四次冗余三次已足够确认双向通道四次增加不必要的延迟ISNInitial Sequence Number的随机化初始序列号不是从 0 开始而是随机生成ISN M F(localhost, localport, remotehost, remoteport, secretkey)防止序列号预测攻击如 TCP 会话劫持防止延迟到达的旧连接数据被误认为新连接的数据3.2 四次挥手断开连接主动关闭方 被动关闭方 │ │ │ ─────────── FIN1, sequ ─────────────── │ │ (FIN_WAIT_1) │ (CLOSE_WAIT) │ │ │ ────────── ACK1, seqv, acku1 ───────── │ │ (FIN_WAIT_2) │ (CLOSE_WAIT) │ │ (继续发送数据...) │ │ │ ────────── FIN1, ACK1, seqw, acku1 ─── │ │ (TIME_WAIT) │ (LAST_ACK) │ │ │ ─────────── ACK1, sequ1, ackw1 ─────── │ │ (TIME_WAIT, 2MSL 后 CLOSED) │ (CLOSED) │ │为什么需要 TIME_WAIT 状态2MSL确保最后的 ACK 被收到如果 ACK 丢失被动关闭方会重发 FIN主动关闭方在 TIME_WAIT 状态可以重发 ACK防止旧连接的数据包干扰新连接等待 2MSLMaximum Segment Lifetime通常 2~4 分钟确保网络中所有旧连接的数据包消失MSL 的典型值Linux 默认 60 秒2MSL 120 秒TIME_WAIT 持续时间TIME_WAIT 过多的问题每个连接占用一个端口端口数有限65535高并发短连接场景如 HTTP/1.0大量连接处于 TIME_WAIT导致端口耗尽解决方案# 启用 TIME_WAIT 复用Linuxsysctl-wnet.ipv4.tcp_tw_reuse1# 复用 TIME_WAIT 连接仅客户端sysctl-wnet.ipv4.tcp_tw_recycle1# 快速回收 TIME_WAITLinux 4.12 已废弃# 更好的方案使用连接池HTTP Keep-Alive、数据库连接池[citation:2]4. TCP 可靠性机制4.1 确认与重传机制累积确认Cumulative ACKTCP 不逐个确认每个报文而是确认已正确收到的最大连续序列号例如收到 Seq 1~1000 和 2001~3000但 1001~2000 丢失ACK 1001表示期望收到 1001暗示 1~1000 已收到选择确认SACKSelective ACKTCP Options 中的 SACK 字段可以精确告知发送方收到了哪些不连续的段例如收到 1~1000 和 2001~3000SACK 可以告知我收到了 2001~3000发送方只需重传 1001~2000而不是重传所有SACK 示例 发送方: [1-1000] [1001-2000] [2001-3000] [3001-4000] ↓ ✗ ↓ ↓ 接收方: 收到 1-1000, 2001-3000, 3001-4000但 1001-2000 丢失 无 SACK: ACK1001发送方不知道 2001-4000 已收到可能重传全部 有 SACK: ACK1001, SACK2001-4000发送方只重传 1001-2000 → SACK 减少不必要的重传提高吞吐量超时重传RTORetransmission TimeoutRTO 基于 RTTRound-Trip Time动态计算Jacobson/Karels 算法SRTT (1 - α) * SRTT α * RTT_sample (α 通常 0.125) RTTVAR (1 - β) * RTTVAR β * |SRTT - RTT_sample| (β 通常 0.25) RTO SRTT 4 * RTTVARRTO 有下限通常 200ms和上限通常 120s快速重传Fast Retransmit收到3 个重复的 ACK立即重传不等待 RTO 超时例如发送 1~1000, 1001~2000, 2001300010012000 丢失接收方收到 2001~3000 后重复 ACK1001期望 1001收到 3 个重复 ACK1001 → 发送方立即重传 1001~2000[citation:3]4.2 滑动窗口与流量控制接收窗口Receive Windowrwnd接收方通过 TCP 头部的 Window 字段告知发送方自己的接收缓冲区大小发送方不能发送超过接收窗口大小的未确认数据接收窗口示例 接收方缓冲区: [已确认] [已接收未确认] [空闲] [空闲] [空闲] ↑ ↑ LastByteRead LastByteRcvd 接收窗口 缓冲区大小 - (LastByteRcvd - LastByteRead) 可接收但尚未发送 ACK 的数据量发送窗口Send Windowswnd发送窗口 min(接收窗口, 拥塞窗口) 发送方缓冲区: [已发送已确认] [已发送未确认] [可发送] [不可发送] ↑ ↑ ↑ LastByteAcked LastByteSent LastByteWritten 发送窗口 LastByteWritten - LastByteAcked 已发送未确认 LastByteSent - LastByteAcked 可用窗口 发送窗口 - 已发送未确认零窗口问题接收方缓冲区满发送 Window0发送方停止发送启动持续定时器Persist Timer持续定时器到期后发送窗口探测Window Probe报文接收方回复当前窗口大小可能仍为 0或已释放空间接收方: Window 0 (缓冲区满) 发送方: 停止发送启动 Persist Timer ... 发送方: [Window Probe] (1 字节数据) 接收方: [ACK, Window0] (仍满) ... 发送方: [Window Probe] 接收方: [ACK, Window1024] (有空间了) 发送方: 恢复发送[citation:4]5. TCP 拥塞控制5.1 拥塞窗口Congestion Windowcwnd拥塞控制是 TCP 的全局流量控制防止发送方过快发送导致网络拥塞路由器缓冲区溢出、丢包。发送窗口的最终计算发送窗口 min(接收窗口 rwnd, 拥塞窗口 cwnd) → 流量控制rwnd限制发送方不超过接收方能力 → 拥塞控制cwnd限制发送方不超过网络能力 → 实际发送速率受两者较小值限制5.2 拥塞控制算法演进算法 1慢启动Slow Start初始: cwnd 1 MSS (Maximum Segment Size, 通常 1460 字节) 每收到一个 ACK: cwnd 1 MSS → 指数增长: 1, 2, 4, 8, 16, ... 慢启动阈值ssthresh 初始值较大如 65535 字节 当 cwnd ssthresh: 慢启动指数增长 当 cwnd ssthresh: 拥塞避免线性增长算法 2拥塞避免Congestion Avoidance每收到一个 ACK: cwnd 1 MSS / cwnd → 线性增长: 每 RTT 增加 1 MSS 例如: cwnd 16 MSS 收到 16 个 ACK每个 ACK 增加 1/16 MSS → 总共增加 1 MSS → cwnd 17 MSS算法 3快重传Fast Retransmit收到 3 个重复 ACK: ssthresh cwnd / 2 cwnd ssthresh 3 * MSS 重传丢失的报文 → 进入快恢复算法 4快恢复Fast Recovery快恢复阶段: 每收到一个重复 ACK: cwnd 1 MSS 允许发送新数据利用重复 ACK 的窗口 收到新数据的 ACK: cwnd ssthresh → 进入拥塞避免拥塞控制完整状态机连接建立 │ ▼ 慢启动 (cwnd 指数增长) │ ├── cwnd ssthresh ──→ 拥塞避免 (cwnd 线性增长) │ │ │ ├── 超时 ──→ 慢启动 │ │ ssthresh cwnd / 2 │ │ cwnd 1 MSS │ │ │ └── 3 个重复 ACK ──→ 快重传 │ │ │ ▼ │ 快恢复 │ │ │ └── 新 ACK ──→ 拥塞避免 │ └── 超时 ──→ 慢启动 ssthresh cwnd / 2 cwnd 1 MSSTCP Reno vs TCP CUBIC算法拥塞窗口恢复适用场景内核默认Reno线性增长传统网络旧版 LinuxCUBIC三次函数增长高带宽延迟网络Linux 2.6.19BBR基于带宽和 RTT 模型Google 推荐Linux 4.9CUBIC 的核心改进拥塞窗口恢复采用三次函数立方函数在远离饱和点时快速增长接近饱和点时缓慢增长更适合高带宽延迟网络如跨洲际连接# 查看当前拥塞控制算法sysctlnet.ipv4.tcp_congestion_control# 切换为 BBRLinux 4.9sysctl-wnet.ipv4.tcp_congestion_controlbbr[citation:5]6. TCP 性能优化6.1 Nagle 算法与延迟确认Nagle 算法目的减少小报文数量提高网络效率规则如果发送缓冲区中的数据不足一个 MSS且有未确认的报文则等待 ACK 后再发送问题与延迟 ACK 结合导致200ms 延迟Nagle 等待 ACKDelayed ACK 等待 200msDelayed ACK目的减少 ACK 数量提高网络效率规则接收方不立即发送 ACK而是等待 200ms 或收到下一个报文后再发送问题与 Nagle 算法冲突导致小数据交互延迟解决方案// 禁用 Nagle 算法TCP_NODELAYSocketsocketnewSocket();socket.setTcpNoDelay(true);// 立即发送不等待 ACK// 或禁用 Delayed ACK系统级Linux// sysctl -w net.ipv4.tcp_no_delay_ack1适用场景交互式应用SSH、游戏→ 禁用 NagleTCP_NODELAY批量传输文件下载→ 启用 Nagle6.2 TCP Fast OpenTFO问题HTTP 短连接每次请求都需要 3 RTTTCP 握手 TLS 握手TFO 原理第一次连接正常三次握手客户端收到 SYNACK 后服务器发送Cookie后续连接客户端在 SYN 中携带 Cookie 和数据0-RTT 建立连接并发送数据首次连接1-RTT 获取 Cookie: Client → Server: SYN TFO Cookie Request Client ← Server: SYNACK TFO Cookie Client → Server: ACK Data 后续连接0-RTT 发送数据: Client → Server: SYN TFO Cookie Data Client ← Server: SYNACK Data Client → Server: ACK# 启用 TCP Fast OpenLinuxsysctl-wnet.ipv4.tcp_fastopen3# 1客户端, 2服务端, 3双向6.3 TIME_WAIT 优化# 查看 TIME_WAIT 数量ss-tan|grepTIME_WAIT|wc-l# 优化方案 1复用 TIME_WAIT仅客户端sysctl-wnet.ipv4.tcp_tw_reuse1# 优化方案 2缩短 TIME_WAIT 时间谨慎sysctl-wnet.ipv4.tcp_fin_timeout30# 默认 60s# 优化方案 3使用连接池推荐# HTTP Keep-Alive、数据库连接池、Redis 连接池6.4 其他内核参数调优参数默认值建议值说明net.core.rmem_max21299216777216接收缓冲区最大值net.core.wmem_max21299216777216发送缓冲区最大值net.ipv4.tcp_rmem4096 87380 62914564096 87380 16777216接收缓冲区动态范围net.ipv4.tcp_wmem4096 16384 41943044096 16384 16777216发送缓冲区动态范围net.ipv4.tcp_max_syn_backlog51265536SYN 队列长度net.core.netdev_max_backlog100065536网卡队列长度net.ipv4.tcp_slow_start_after_idle10空闲后是否重置 cwnd[citation:6]7. 面试官追问与高分回答模板追问 1“说一下 TCP 协议”低分回答“TCP 是面向连接的传输层协议通过三次握手建立连接四次挥手断开连接。”没有深入机制高分回答TCP 是传输层协议在不可靠的 IP 网络之上提供面向连接、可靠传输、字节流、全双工的通信服务。核心机制连接管理三次握手建立连接SYN → SYNACK → ACK四次挥手断开连接FIN → ACK → FIN → ACKTIME_WAIT 2MSL 确保可靠关闭。可靠性累积确认 选择确认SACK减少重传超时重传RTO 基于 RTT 动态计算快速重传3 个重复 ACK 立即重传。流量控制滑动窗口rwnd接收方通过 Window 字段告知可用缓冲区零窗口时发送窗口探测。拥塞控制慢启动指数增长→ 拥塞避免线性增长→ 快重传 快恢复丢包后快速恢复。现代内核默认使用 CUBIC 算法高带宽延迟网络推荐使用 BBR。追问 2“为什么是三次握手不是两次或四次”高分回答三次握手是为了确认双方的收发能力同时防止历史重复连接初始化两次握手的问题客户端发送 SYN 后如果延迟到达旧连接的数据服务器回复 SYNACK 后直接建立连接。但客户端可能已关闭导致服务器浪费资源维护一个无效连接。同时两次无法确认客户端的接收能力。三次握手客户端发送 SYN我能发服务器回复 SYNACK我能收发客户端回复 ACK我能收。双方确认收发能力同时 ISN 随机化防止序列号预测攻击。四次握手冗余三次已足够确认双向通道四次增加不必要的 RTT。另外三次握手还能同步双方的初始序列号ISN为后续可靠传输奠定基础。追问 3“TIME_WAIT 状态是什么为什么需要 2MSL”高分回答TIME_WAIT 是主动关闭方在发送最后一个 ACK 后进入的状态持续 2MSLMaximum Segment Lifetime通常 120 秒。需要 2MSL 的两个原因确保最后的 ACK 被收到如果 ACK 丢失被动关闭方会重发 FIN主动关闭方在 TIME_WAIT 状态可以重发 ACK。2MSL 足够等待一个 FIN 和一个 ACK 的往返。防止旧连接的数据包干扰新连接等待网络中所有旧连接的数据包消失避免新连接相同四元组收到旧数据。TIME_WAIT 过多的问题高并发短连接场景如 HTTP/1.0端口耗尽65535 限制。解决方案启用tcp_tw_reuse复用 TIME_WAIT 连接、使用连接池Keep-Alive、或升级到 HTTP/2长连接复用。追问 4“TCP 的滑动窗口是怎么工作的流量控制和拥塞控制有什么区别”高分回答滑动窗口是 TCP 实现流量控制和可靠传输的核心机制。流量控制端到端接收方通过 TCP 头部的 Window 字段告知发送方自己的接收缓冲区大小rwnd发送方不能发送超过 rwnd 的未确认数据防止发送方过快导致接收方缓冲区溢出拥塞控制全局网络发送方维护拥塞窗口 cwnd根据网络状况动态调整慢启动cwnd 指数增长→ 拥塞避免cwnd 线性增长→ 快重传/快恢复丢包后快速恢复防止发送方过快导致网络拥塞路由器缓冲区溢出核心区别流量控制是端到端的解决接收方处理能力不足拥塞控制是全局网络的解决网络中间设备能力不足实际发送窗口 min(rwnd, cwnd)受两者较小值限制追问 5“TCP 和 UDP 怎么选什么场景用哪个”高分回答TCP 和 UDP 的选择取决于业务对可靠性、延迟、吞吐量的优先级选 TCP 的场景需要可靠传输HTTP/HTTPS、FTP、SSH、SMTP数据完整性要求高文件传输、金融交易、数据库同步需要流量控制和拥塞控制广域网、高带宽延迟网络选 UDP 的场景低延迟优先实时音视频WebRTC、在线游戏、DNS广播/多播视频直播、物联网设备上报应用层自定义可靠机制QUICHTTP/3、KCP游戏加速中间方案需要可靠但延迟敏感QUIC基于 UDP 实现可靠传输0-RTT需要有序但可容忍丢包TCP 禁用 NagleTCP_NODELAY追问 6“TCP 的拥塞控制算法有哪些BBR 相比 CUBIC 有什么优势”高分回答TCP 拥塞控制算法经历了三代演进Reno传统算法丢包后 ssthreshcwnd/2cwnd1进入慢启动。问题丢包后才反应高带宽网络利用率低。CUBICLinux 2.6.19 默认cwnd 恢复采用三次函数增长远离饱和点快速增长接近饱和点缓慢增长。适合高带宽延迟网络但仍基于丢包检测。BBRGoogle 开发Linux 4.9 支持。不依赖丢包而是基于带宽和 RTT 的测量模型直接计算最优发送速率。BBR 的优势不依赖丢包在浅缓冲区网络如数据中心性能更好启动更快快速探测带宽与 CUBIC 共存时更公平不抢占 CUBIC 的带宽抗丢包能力强丢包不认为是拥塞配置sysctl -w net.ipv4.tcp_congestion_controlbbr需要 Linux 4.9 内核。8. 方案选型速查表场景推荐协议关键配置说明Web 应用TCP HTTP/2Keep-Alive, TLS 1.3长连接复用减少握手实时音视频UDP QUIC0-RTT, 连接迁移低延迟抗丢包文件传输TCP CUBIC/BBR大窗口, 大缓冲区高吞吐在线游戏UDP KCP快速重传, 拥塞控制低延迟优先数据库同步TCP BBR可靠传输, 高吞吐数据完整性物联网上报UDP CoAP轻量级, 低功耗设备资源受限高并发 APITCP 连接池Keep-Alive, 复用减少 TIME_WAIT面试官想要的满分总结TCP 是互联网传输层的基石理解它必须抓住连接管理、可靠性、流量控制、拥塞控制四大核心机制连接管理三次握手确认双方收发能力ISN 随机化防止攻击四次挥手确保可靠关闭TIME_WAIT 2MSL 防止旧数据干扰。高并发短连接场景注意 TIME_WAIT 端口耗尽问题。可靠性累积确认 SACK 精确重传RTO 基于 RTT 动态计算快速重传3 个重复 ACK避免等待超时。序列号和确认号保证数据有序、不丢、不重。流量控制滑动窗口rwnd限制发送方不超过接收方能力零窗口时发送窗口探测。与拥塞控制cwnd共同决定实际发送窗口 min(rwnd, cwnd)。拥塞控制慢启动指数增长→ 拥塞避免线性增长→ 快重传/快恢复丢包后快速恢复。现代内核推荐 CUBIC高带宽延迟网络或 BBRGoogle 推荐基于带宽模型。最后记住TCP 是为可靠性设计的如果业务需要低延迟且可容忍丢包考虑 UDP 应用层自定义可靠机制如 QUIC。生产环境注意 Nagle 与 Delayed ACK 的冲突、TIME_WAIT 优化、内核参数调优。觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~