跳到主要内容
版本:1.0

传输层:TCP 与 UDP(面试第一大难点)

3.1 UDP:用户数据报协议​

特点:

  • 无连接:发送前不需要握手建连;
  • 不可靠:不保证到达、不保证顺序、不确认、不重传;
  • 面向报文:应用层交给 UDP 多长的报文,UDP 就照样发送,保留报文边界(一次 send 对应一次接收);
  • 首部开销小:仅 8 字节(源端口、目的端口、长度、校验和);
  • 支持一对多:支持单播、组播、广播;
  • 实时性好:没有拥塞控制、重传的等待,延迟稳定。

适用场景:DNS 查询、DHCP、音视频直播(RTP)、网络游戏、SNMP、以及 QUIC(HTTP/3 的底层传输)。

3.2 TCP:传输控制协议​

特点:

  • 面向连接:通信前必须三次握手建立连接;
  • 可靠传输:确认应答、超时重传、数据校验、去重与按序交付;
  • 面向字节流:数据被当成无边界的字节流(需要应用层自己处理粘包/拆包);
  • 全双工:双方都可同时收发,两端各有发送/接收缓冲区;
  • 流量控制 + 拥塞控制:防止淹没接收方、防止压垮网络;
  • 首部 20~60 字节。

TCP 靠什么保证可靠(靠机制和字段)——面试标准答法:

  1. 序列号 + 确认应答(ACK):每个字节编号,接收方确认已收到的数据边界;
  2. 超时重传:发出后启动定时器,超时未收到 ACK 就重传(RTO 根据往返时延 RTT 自适应计算);
  3. 快速重传:收到 3 个重复 ACK 立即重传,不必等超时;
  4. 校验和:检测首部和数据在传输中的比特差错,出错直接丢弃;
  5. 去重与排序:按序列号重组乱序到达的段,丢弃重复段;
  6. 流量控制(滑动窗口):不淹没接收方;
  7. 拥塞控制:不压垮网络。

3.3 三次握手(必考)​

流程(初始双方处于 CLOSED / LISTEN):

  1. 第一次:客户端 → 服务端发 SYN 报文,seq = x(客户端初始序列号 ISN),客户端进入 SYN_SENT;
  2. 第二次:服务端 → 客户端发 SYN + ACK 报文,seq = y(服务端 ISN),ack = x + 1,服务端进入 SYN_RCVD;
  3. 第三次:客户端 → 服务端发 ACK 报文,ack = y + 1,双方进入 ESTABLISHED。

第三次握手理论上可以携带应用数据(前两次不行)。

为什么是三次,不是两次?

  • 核心原因:防止历史(失效)连接请求建立连接,同步双方初始序列号。 两次握手下,若客户端一个旧的 SYN 迟到,服务端回 SYN+ACK 后就直接建连并占用资源等待数据,而客户端根本不理会,服务端白白等待(旧连接的坑);
  • 三次握手让双方都确认了「自己的发送、接收能力与对方的发送、接收能力都正常」:
    • 客户端:收到 SYN+ACK → 我的发送、接收 OK,对方发送、接收 OK;
    • 服务端:收到第三次 ACK → 我的发送、接收 OK,对方发送、接收 OK;
  • 两次握手无法让服务端确认「客户端能收到自己的报文」;
  • 初始序列号 ISN 随机生成的原因:防止上一次相同四元组连接的历史报文被误当作本次数据;增加外部猜测序列号的难度(防伪造注入)。

扩展:SYN Flood 攻击——攻击者伪造源 IP 大量发 SYN 不回 ACK,服务端 SYN_RCVD 半连接队列被占满。防御:SYN Cookie(不保存半连接状态,把信息编码进 SYN+ACK 的序列号)、调大 backlog、防火墙限速。

3.4 四次挥手(必考)​

流程(假设客户端主动关闭):

  1. 第一次:客户端发 FIN(seq = u),进入 FIN_WAIT_1;
  2. 第二次:服务端回 ACK(ack = u + 1),进入 CLOSE_WAIT;客户端收到后进入 FIN_WAIT_2——此时连接处于半关闭,服务端仍可向客户端发数据;
  3. 第三次:服务端数据发完,发 FIN(seq = w),进入 LAST_ACK;
  4. 第四次:客户端回 ACK(ack = w + 1),进入 TIME_WAIT,等待 2MSL 后关闭;服务端收到 ACK 即关闭。

为什么挥手四次,握手三次?

  • 握手时 SYN 和 ACK 可以合并成一个 SYN+ACK 报文;
  • 挥手时 TCP 是全双工,两个方向要分别关闭:被动方收到 FIN 时可能还有数据没发完(半关闭状态),所以先回 ACK,等数据发完再发 FIN——ACK 与 FIN 通常无法合并(除非数据恰好发完,此时部分实现会合并成 FIN+ACK)。

TIME_WAIT 详解(高频):

  • 为什么等待 2MSL(MSL = 报文最大生存时间):
    1. 保证最后的 ACK 可达:若第四次 ACK 丢失,服务端会重传 FIN;客户端在 TIME_WAIT 期间还能重发 ACK。若直接关闭,服务端将收不到 ACK 而无法正常关闭;
    2. 让本连接的所有旧报文在网络中自然消亡,防止延迟的报文串进相同四元组的新连接。
  • TIME_WAIT 过多的危害:出现在主动关闭方(通常是客户端或负载均衡器)。高并发短连接场景会占用大量端口/内存,客户端源端口耗尽(可用端口约 6 万个)后无法建新连接。
  • 优化:使用长连接 / 连接池复用;tcp_tw_reuse(仅客户端、需时间戳支持)复用 TIME_WAIT 端口;so_reuseaddr 允许监听复用。

CLOSE_WAIT 详解(高频):

  • 出现在被动关闭方:收到对方 FIN、回完 ACK 后进入 CLOSE_WAIT,等待本方应用程序调用 close()。
  • 大量 CLOSE_WAIT 堆积 = 代码 Bug:服务端收到 FIN 后一直不调用 close(),连接泄漏。常见原因:异常分支漏关连接、连接池归还逻辑缺陷、线程池打满导致处理不过来、响应完请求没有正确关闭。
  • 处理方式:ss -tanp | grep CLOSE_WAIT 定位进程 → 代码审查连接释放逻辑(try/finally 关闭)→ 修复后重启(需要开发一起处理)。

TCP 状态机速记:服务端两大堆积异常——大量 SYN_RCVD(SYN Flood)、大量 CLOSE_WAIT(程序没关连接);客户端常见 TIME_WAIT 堆积(主动关短连接)。

3.5 TCP 流量控制:滑动窗口​

  • 目的:匹配收发双方的处理速度,不淹没接收方。
  • 机制:接收方在每个 ACK 中用 rwnd(接收窗口) 字段通告自己接收缓冲区的剩余空间;发送方未确认的在途数据量不得超过 rwnd。
  • 发送窗口内部分为四段:已发送已确认 | 已发送未确认(可发送)| 允许发送未发送 | 不可发送。
  • 零窗口:接收方缓冲区满时通告 rwnd=0,发送方暂停发送并周期性发窗口探测报文,防止死锁;接收方腾出空间后通告新窗口。
  • 糊涂窗口综合征:接收方每次只腾出很小的窗口导致效率极低,通过延迟通告 + Nagle 算法缓解。

3.6 TCP 拥塞控制(必考,讲现象,不用推公式)​

  • 目的:防止过多数据注入网络,不压垮网络(与流量控制的区别:流量控制是端到端、保护接收方;拥塞控制是全局性、保护网络)。
  • 发送方维护拥塞窗口 cwnd,实际发送窗口 = min(rwnd, cwnd)。
  • 四个算法阶段(以拥塞窗口随时间变化描述):

① 慢启动(Slow Start):连接建立初期 cwnd 从小值(如 1~10 MSS)开始,每收到一个 ACK,cwnd 增加;效果是每个 RTT 翻倍(指数增长),直到达到阈值 ssthresh。

② 拥塞避免(Congestion Avoidance):cwnd ≥ ssthresh 后,每个 RTT 只 +1 MSS(线性增长),小心试探网络上限。

③ 快重传(Fast Retransmit):接收方收到失序报文段时重复确认最后有序的 ACK;发送方连续收到 3 个重复 ACK,判定该报文丢失,不等超时立即重传。

④ 快恢复(Fast Recovery):配合快重传使用——发生 3 个重复 ACK 时,令 ssthresh = cwnd / 2,cwnd = 新 ssthresh,直接进入拥塞避免线性增长(不回到慢启动)。

超时触发(重度拥塞):RTO 超时说明网络很糟糕,ssthresh = cwnd / 2,cwnd = 1 MSS,重新慢启动。

一句话总结:丢包轻微(3 个重复 ACK)→ 减半后线性涨;丢包严重(超时)→ 归 1 指数涨。

3.7 TCP vs UDP 对比与选型​

维度TCPUDP
连接面向连接(三次握手)无连接
可靠性可靠(确认、重传、有序)尽力而为,不可靠
数据单位面向字节流(无边界)面向报文(有边界)
首部开销20~60 字节8 字节
拥塞/流量控制有无
传输效率较低(机制开销)高、实时性好
通信模式一对一单播/组播/广播
典型应用HTTP/HTTPS、SSH、MySQL、邮件DNS、DHCP、直播、游戏、QUIC

选型建议:要完整正确(文件传输、交易、命令执行)→ TCP;要实时低延迟、可容忍丢包(音视频、游戏)→ UDP;要「快且可靠」→ 基于 UDP 在应用层自建可靠机制(QUIC 就是这个思路)。

3.8 面试真题​

Q1:为什么握手 3 次、挥手 4 次? 见 3.3 / 3.4——握手可合并(SYN+ACK),挥手因全双工半关闭一般不能合并;三次是双方收发能力都确认 + 防历史连接的最少次数。

Q2:TCP 怎么保证可靠传输? 见 3.2 的七点机制(确认应答、超时/快速重传、校验和、去重排序、流量控制、拥塞控制——靠机制和字段)。

Q3:TIME_WAIT 和 CLOSE_WAIT 分别出现在哪一方、什么原因? 见 3.4:TIME_WAIT 在主动关闭方、等 2MSL;CLOSE_WAIT 在被动关闭方、应用没调 close()。