TCP 面试手册
覆盖 TCP 三次握手、四次挥手、确认重传、流量控制、拥塞控制和 TIME-WAIT 等面试高频考点。
文章目录
知识地图
graph TD
A[TCP 协议] --> B[连接管理]
A --> C[可靠传输]
A --> D[性能机制]
B --> B1[三次握手]
B --> B2[四次挥手]
B --> B3[TIME-WAIT]
B --> B4[SYN Flood]
C --> C1[序列号与确认]
C --> C2[超时重传]
C --> C3[快速重传]
D --> D1[滑动窗口]
D --> D2[拥塞控制]
D --> D3[Nagle 算法]核心速记卡
| 概念 | 一句话定义 | 关键限制 |
|---|---|---|
| 三次握手 | SYN → SYN+ACK → ACK,同步双方初始序列号 | 防止旧重复连接请求建立无效连接 |
| 序列号 | 每个字节有唯一编号,用于有序交付和去重 | 初始序列号应随机化防攻击 |
| 滑动窗口 | 接收方通告可接收的字节数,发送方据此限速 | 窗口为 0 时发送方停止发数据 |
| 拥塞控制 | 发送方根据拥塞信号动态调整发送速率 | 具体算法与窗口更新规则取决于协议栈实现 |
| TIME-WAIT | 主动关闭方等待 2MSL 确保最后 ACK 送达 | 具体时长由实现决定;大量短连接会增加端口压力 |
基础问答
Q: 为什么 TCP 需要三次握手建立连接?
答: 防止旧的、已失效的连接请求报文突然到达服务器导致错误建立连接。如果只有两次握手,一个在网络中延迟的旧 SYN 到达服务器时,服务器会回复 SYN+ACK 并直接进入 ESTABLISHED 状态分配资源。三次握手中,客户端可以确认自己确实想建立这个连接(发送最后的 ACK),从而拒绝过期的连接请求。
Q: 四次挥手过程中为什么有 TIME-WAIT 状态?
答: TIME-WAIT 持续 2MSL(Maximum Segment Lifetime),具体秒数由协议栈实现决定。它有两个作用:一是确保主动关闭方发送的最后一个 ACK 丢失后,仍能收到对方重传的 FIN 并再次确认;二是让本连接期间在网络中滞留的报文有足够时间被丢弃,不会干扰使用相同四元组的后续连接。
Q: TCP 如何保证数据不丢失、不重复、不乱序?
答: 发送方按字节流位置分配序列号。接收方按序列号重组数据,检测到缺口时会重复发送当前累计确认号,也就是“下一次期望收到的字节序号”;发送方收到足够的重复 ACK 后可以快速重传。重复的数据段会按序列号识别并丢弃。
深入追问
Q: 经典 TCP Reno 中的慢启动、拥塞避免、快速重传和快速恢复分别解决什么问题?
答:
- 慢启动:解决“尚不知道网络容量”的问题。从较小的初始拥塞窗口开始,按收到的确认快速增长;初始窗口大小取决于所遵循的 RFC 和协议栈实现。
- 拥塞避免:解决”接近网络容量后如何稳定”的问题。线性增长 cwnd,避免剧烈的速率振荡。
- 快速重传:解决”必须等到超时才发现丢包太慢”的问题。收到 3 个重复 ACK 即立即重传。
- 快速恢复:解决“检测到部分丢包后不必像超时那样完全回到初始阶段”的问题。具体窗口调整规则依赖 Reno/NewReno 等算法及实现。
Q: 滑动窗口和拥塞窗口有什么区别?
答: 发送方的实际发送窗口 = min(接收方通告窗口, 拥塞窗口)。接收方通告窗口反映接收方的处理能力——“我能吃多少”;拥塞窗口反映发送方对网络容量的估计——“网络能传多少”。两者取最小值。
工程场景题
场景:嵌入式设备通过 TCP 发送数据,抓包发现多个小包被延迟或合并发送
分析思路:
- 检查 Nagle 算法是否启用:存在未确认数据时,它会暂存后续小块数据,直到收到 ACK 或积累到足够大小。
- 如果应用协议是低延迟的小请求-响应模式,可以评估启用
TCP_NODELAY;如果是批量传输模式,通常保留 Nagle 更合适。 - 也可能与对端延迟确认(Delayed ACK)产生不良交互。
场景:服务器上 netstat -an 显示大量 CLOSE-WAIT 连接不释放
分析思路:
CLOSE-WAIT 表示对方已发送 FIN,但本地应用还没有调用 close()。这说明应用层代码存在 bug——在收到对端关闭信号后没有正确关闭 socket。
检查:应用是否正确处理了 read() 返回 0(对端关闭连接)的情况?收到 0 后是否调用了 close()?
易错点
- 误区:“TCP 是可靠协议,所以数据 100% 能到” → TCP 在连接可维持时提供可靠、有序字节流;持续超时或网络中断后,协议栈会放弃重传并向应用报告连接错误,不保证一定发送 RST。
- 误区:“TCP 有消息边界” → TCP 是字节流协议,没有消息边界。应用层必须自己设计帧协议。
- 误区:“SYN 包中的序列号从 0 开始” → 初始序列号 ISN 应该是随机生成的(防序列号预测攻击)。
- 误区:“TCP 关闭永远严格需要四个独立报文” → 常见流程是四次交互,因为被动关闭方可能还有数据要发送;如果它收到 FIN 时也已准备关闭,ACK 和 FIN 可以合并在同一个报文段中。
一句话总结
TCP 的可靠性建立在”每个字节编号、未确认则重传”的基础上,而三次握手防旧连接、滑动窗口做流控、拥塞控制适配网络——这四个机制是任何 TCP 面试的必考点。