面试题:游戏、直播为什么常用 UDP?KCP 是什么?为什么比 TCP 更适合低延迟场景?
一、核心思路(一句话)
实时业务核心不是"绝对可靠",而是"低延迟、及时到达";UDP负责低开销传输,KCP在UDP之上补充可靠传输、快速重传、流控等能力,通过增加带宽开销换取更低的丢包恢复时延。
二、先回答:游戏到底使用 TCP 还是 UDP?
标准答案
不能简单说"游戏都使用 UDP"。
实时对战、语音、实时互动等场景通常更关注低延迟和及时性,因此常见方案是:
text
应用
│
├── 实时状态/操作指令
│ ↓
│ UDP
│ ↓
│ 自定义可靠机制
│ / KCP / 其他协议
│
└── 登录、支付、资源下载等
↓
TCP / HTTPS
原因是不同数据对"可靠性"和"实时性"的要求不同。
例如:
text
玩家移动指令:
100ms前的"向左移动"
↓
现在才到
↓
即使可靠,也已经失去实时价值
所以实时业务往往遵循:
旧数据晚到,有时不如丢掉;新数据必须尽快到。
但实际大型游戏通常是多协议、多通道组合,并不是整个游戏只使用 UDP。
三、UDP 和 TCP 的核心区别
1. UDP
UDP提供的是:
text
应用
↓
UDP
↓
IP
↓
网络
UDP本身不保证:
- 一定到达
- 按顺序到达
- 不重复
- 自动重传
- 拥塞控制
- 可靠字节流
因此可以理解为:
UDP只负责尽可能把数据报交给IP网络,不负责把"可靠传输"这件事情全部做好。
2. TCP
TCP在IP之上增加了大量传输控制能力:
text
TCP
├── 序列号
├── ACK
├── 超时重传
├── 快速重传
├── 流量控制
├── 拥塞控制
├── 有序交付
└── 可靠字节流
因此:
text
TCP = UDP/IP之上的一整套可靠传输机制
更准确地说,TCP并不是简单的"UDP + 可靠性",两者在传输语义和实现机制上都有明显差异。
四、为什么实时业务不直接使用 TCP?
核心矛盾:
TCP追求可靠、有序、稳定;实时业务追求及时。
例如:
text
发送:
A → B → C → D
假设B丢失:
A → 到达
B → 丢失
C → 到达
D → 到达
TCP必须保证应用层看到:
text
A B C D
因此B没有恢复之前,后面的数据可能受到队头阻塞(Head-of-Line Blocking)影响。
对于文件下载:
text
B晚一点到
↓
没关系
↓
最终完整下载
但对于游戏:
text
B = 100ms之前的移动指令
现在:
B终于到了
问题:
玩家已经移动到下一位置了
所以实时业务更关注:
text
延迟
↓
丢包恢复速度
↓
实时性
而不是单纯追求:
text
100%可靠 + 严格有序
五、KCP到底是什么?
这是面试最容易答错的地方。
一句话
KCP不是TCP、UDP之外的第三种底层传输协议,而是一套可以运行在UDP等底层传输之上的可靠传输算法/协议实现。
KCP官方实现本质上是轻量级算法库,本身不负责真正的网络收发,应用需要提供底层发送回调;常见使用方式就是:
text
应用
↓
KCP
↓
UDP
↓
IP
↓
网络
KCP官方实现明确提供了 ikcp_send、ikcp_input、ikcp_update 等接口,并通过 output 回调把KCP数据交给底层网络发送。(GitHub)
所以:
text
UDP
= 底层数据报传输
KCP
= 在UDP之上增加可靠传输能力
六、KCP解决了UDP什么问题?
裸UDP:
text
发送
↓
UDP
↓
网络
↓
可能丢包
KCP增加:
text
应用数据
↓
KCP
├── 序列号
├── ACK
├── 超时重传
├── 快速重传
├── 接收窗口
├── 流量控制
└── 可配置拥塞控制
↓
UDP
↓
网络
因此可以把KCP理解成:
"UDP + 应用层可靠传输机制",并且针对低延迟进行了激进优化。
七、KCP为什么比TCP更快?
这里不要回答:
"KCP就是TCP,但是速度更快。"
正确答案应该拆成几个机制。
主要矛盾
丢包发生以后,TCP和KCP谁能更快恢复数据。
KCP官方实现主要通过以下机制降低传输延迟:
text
KCP低延迟
│
┌──────────────┼──────────────┐
↓ ↓ ↓
更积极的RTO 快速重传 可关闭拥塞控制
│ │ │
↓ ↓ ↓
更快发现丢包 不必等超时 减少主动降速
八、机制一:更积极的超时重传
TCP的RTO并不是简单的:
text
RTO = 2 × RTT
标准TCP会根据:
text
SRTT
RTTVAR
等参数计算RTO,并在重传超时后进行退避。RFC 6298规定的基础计算形式为:
text
RTO = SRTT + max(G, 4 × RTTVAR)
并规定了相应的重传退避机制。(RFC 编辑器)
KCP则提供了更激进的低延迟策略。
KCP源码中可以看到:
text
IKCP_RTO_MIN = 100ms
IKCP_RTO_NDL = 30ms
快速模式可以降低最小RTO,从而更早进行丢包检测。(GitHub)
所以面试不要死背:
text
TCP = 2倍
KCP = 1.5倍
而应该说:
KCP通过更积极的RTO和快速模式缩短丢包恢复等待时间。
九、机制二:快速重传
这是KCP非常重要的优化点。
假设:
text
发送:
1 2 3 4 5
网络中:
text
1 √
2 ×
3 √
4 √
5 √
接收端可能继续反馈后面的ACK。
发送端发现:
text
ACK 1
ACK 3
ACK 4
ACK 5
那么可以推断:
text
2可能丢失
KCP可以根据配置的快速重传阈值提前重传2,而不是一直等待RTO超时。
KCP的:
text
ikcp_nodelay(
kcp,
nodelay,
interval,
resend,
nc
)
中:
text
resend
就是快速重传相关配置。
官方实现支持例如:
text
resend = 2
即出现一定数量的ACK跳跃后直接触发快速重传。(GitHub)
十、机制三:选择性重传
核心思想:
text
只重传真正丢失的数据
例如:
text
发送:
1 2 3 4 5
实际:
1 √
2 ×
3 √
4 √
5 √
恢复时:
text
TCP传统机制
→ 根据具体实现和协议状态进行重传控制
KCP
→ 针对丢失的数据段进行选择性重传
所以KCP可以减少不必要的数据重复发送。
十一、机制四:拥塞控制可以配置
KCP并不是"天然没有拥塞控制"。官方实现存在:
text
nc
参数:
text
nc = 0
表示正常拥塞控制。
text
nc = 1
表示关闭传统拥塞控制。
例如:
text
ikcp_nodelay(kcp, 1, 10, 2, 1);
可以配置:
text
nodelay = 1
interval = 10ms
resend = 2
nc = 1
即:
text
低延迟
+
快速重传
+
关闭拥塞控制
官方文档也明确说明,KCP可以通过配置牺牲一定公平性和带宽利用率来换取更低延迟。(GitHub)
十二、为什么关闭拥塞控制会更快?
正常情况下:
text
网络拥塞
↓
丢包
↓
判断网络可能拥塞
↓
降低发送速度
这样做的好处:
text
保护网络
提高公平性
但实时游戏可能更关注:
text
当前操作必须尽快送达
因此某些场景可以选择:
text
减少拥塞退让
↓
保持较高发送速率
↓
降低延迟
代价:
text
更高带宽
更低网络公平性
可能加剧拥塞
所以:
KCP的"快"不是凭空产生的,而是用带宽、网络公平性和部分拥塞控制能力换来的。
十三、KCP的完整工作流程
这是面试时最值得画出来的结构图。
text
应用层
│
│ ikcp_send()
↓
┌───────────────┐
│ KCP │
│ │
│ 序列号 │
│ ACK │
│ RTO │
│ 快速重传 │
│ 选择性重传 │
│ 流控 │
│ 拥塞控制 │
└───────┬───────┘
│
output回调
↓
UDP
↓
IP
↓
Internet
↓
UDP
↓
┌───────────────┐
│ KCP │
│ │
│ ikcp_input() │
│ ACK处理 │
│ 丢包检测 │
│ 重排 │
└───────┬───────┘
↓
应用层 ikcp_recv()
KCP官方使用方式就是:
text
ikcp_send()
↓
KCP内部缓存
↓
ikcp_update()
↓
output()
↓
UDP发送
收到UDP数据后:
text
UDP receive
↓
ikcp_input()
↓
KCP处理ACK / DATA
↓
ikcp_recv()
(GitHub)
十四、KCP为什么需要 ikcp_update()?
这是深入理解KCP很重要的一点。
ikcp_send() 不等于立即完成整个网络发送和重传管理。
KCP内部需要周期性执行:
text
ikcp_update(now)
它负责推动KCP状态机:
text
当前时间
↓
检查ACK
↓
检查超时
↓
检查需要重传的数据
↓
发送ACK
↓
执行重传
↓
调用output()
所以实际结构类似:
text
应用发送数据
↓
ikcp_send()
↓
进入KCP发送队列
↓
ikcp_update()
↓
KCP决定什么时候真正发送
↓
output()
↓
UDP
这也是理解KCP源码的关键入口。
十五、KCP有哪些核心数据结构?
如果面试官继续追源码,可以继续往下说:
text
ikcpcb
│
├── snd_queue
│ ↓
│ 等待发送的数据
│
├── snd_buf
│ ↓
│ 已经发送但尚未确认的数据
│
├── rcv_buf
│ ↓
│ 已收到但可能乱序的数据
│
├── rcv_queue
│ ↓
│ 已经可以交给应用的数据
│
├── acklist
│ ↓
│ 等待发送的ACK
│
├── snd_wnd
│ ↓
│ 发送窗口
│
├── rcv_wnd
│ ↓
│ 接收窗口
│
├── rx_srtt
│ ↓
│ 平滑RTT
│
├── rx_rto
│ ↓
│ 重传超时
│
└── fastresend
↓
快速重传阈值
这部分比单纯说"UDP+可靠性"更接近源码层面。
十六、KCP的代价是什么?
不能只回答"KCP更快"。
核心是:
text
低延迟
↕
带宽 / 公平性 / 网络压力
KCP官方资料给出的设计目标就是以额外带宽开销换取更低传输延迟;官方README描述其典型额外带宽开销约为10%~20%,并强调这是具体实现和配置下的性能取舍,而不是固定保证值。(GitHub)
因此:
text
TCP
↓
更强调可靠性、拥塞控制、公平性
KCP
↓
可以更激进地追求低延迟
代价
↓
更多带宽
更多协议状态
更复杂的应用层实现
十七、UDP丢包严重怎么办?
text
方案一:改善底层网络
方案二:应用层增加冗余
方案一:优化网络链路
例如:
text
普通公网
↓
专线 / SD-WAN / 软件组网 / 多线路
↓
改善跨地域网络质量
注意:
不能简单说"国内运营商会优先丢UDP"。
真实网络行为取决于:
text
运营商
网络设备
拥塞情况
QoS策略
NAT
防火墙
线路
地区
网络协议
因此更准确的面试表达是:
UDP没有TCP那种面向连接的传输保证,在部分网络环境下可能面临更明显的丢包、NAT穿透或QoS差异问题;KCP只能解决传输层以上的可靠传输,无法从根本上修复底层链路质量。
十八、方案二:前向纠错 FEC
FEC:
Forward Error Correction,前向纠错。
核心思想:
text
原始数据
A B C D
↓
额外生成冗余数据
P Q
↓
一起发送
A B C D P Q
即使部分数据丢失:
text
A √
B √
C ×
D √
P √
Q ×
接收端仍可能利用:
text
A B D P
恢复:
text
C
这样就可以:
text
丢包
↓
不一定等待重传
↓
直接利用冗余恢复
这对于:
text
实时音视频
实时游戏
高丢包网络
特别有价值。
十九、FEC和KCP是什么关系?
不能简单说:
text
UDP
↓
FEC
↓
KCP
因为:
FEC不是KCP的核心组成部分。
更准确的架构可以是:
text
应用
↓
KCP
↓
FEC
↓
UDP
或者:
text
应用
↓
FEC + 自定义可靠传输
↓
UDP
具体取决于协议栈设计。
两者解决的问题不同:
text
KCP
→ 丢包后:重新发送
FEC
→ 丢包后:利用冗余直接恢复
二十、KCP + FEC为什么可以降低实时延迟?
传统可靠机制:
text
数据丢失
↓
等待ACK
↓
判断丢包
↓
重传
↓
等待再次到达
FEC:
text
数据丢失
↓
已有冗余
↓
直接恢复
因此:
text
KCP
解决:
可靠传输
FEC
解决:
减少重传等待
组合后:
text
UDP
↓
FEC
↓
KCP
↓
应用
在高丢包场景下,可以降低单纯依赖重传造成的延迟。
但代价是:
text
冗余数据
↓
额外带宽
所以本质仍然是:
用带宽换延迟。
二十一、为什么不能把KCP理解成"比TCP快30%~40%"?
面试中最好不要把:
text
KCP比TCP快30%~40%
当成绝对结论。
因为实际性能取决于:
text
RTT
丢包率
带宽
拥塞
窗口
MTU
KCP参数
TCP实现
操作系统
网络路径
业务数据量
KCP官方README确实给出了30%~40%平均传输速度改善的设计/测试描述,但这是特定测试和配置下的数据,不代表所有网络环境都固定快30%~40%。(GitHub)
面试应该说:
KCP通过更积极的丢包恢复、快速重传、可配置的拥塞控制等机制,在特定网络和配置下可以降低传输延迟,但不是所有场景都必然比TCP快。
二十二、主要矛盾和次要矛盾
主要矛盾
text
可靠性
VS
实时性
TCP:
text
更偏向:
可靠 + 有序
UDP:
text
更偏向:
低开销 + 实时性
KCP:
text
UDP基础
+
可靠传输
+
低延迟优化
次要矛盾
text
带宽
VS
延迟
网络公平性
VS
低延迟
重传
VS
FEC冗余
公网质量
VS
应用层优化
二十三、面试最容易被追问的几个问题
Q1:KCP是TCP吗?
不是。
text
TCP
→ 操作系统实现的传输层协议
KCP
→ 应用层实现的可靠传输协议/算法
通常运行在UDP之上
Q2:KCP是UDP吗?
也不是。
text
UDP
→ 底层传输协议
KCP
→ UDP之上的可靠传输机制
Q3:KCP为什么比UDP可靠?
因为它自己实现:
text
序列号
ACK
超时重传
快速重传
窗口
有序组装
Q4:KCP为什么比TCP快?
不要回答:
"因为UDP比TCP快。"
这是错误的。
正确回答:
KCP利用UDP作为底层数据报传输,在应用层重新实现可靠传输,并通过更积极的RTO、快速重传、选择性重传以及可配置拥塞控制等方式降低丢包恢复延迟。
Q5:KCP是不是没有拥塞控制?
不是。
KCP有拥塞控制,并且可以通过配置关闭传统拥塞控制。(GitHub)
Q6:KCP能解决网络丢包吗?
只能解决一部分。
text
KCP
↓
可以:
发现丢包
重传丢包
降低恢复时间
不能:
改变物理链路质量
增加运营商带宽
消除严重网络拥塞
保证UDP一定不被丢弃
二十四、最终满分答案
游戏、实时互动等业务并不是简单地"只使用UDP",而是通常会根据数据类型选择不同的传输方式。实时状态和操作指令更关注低延迟,因此常采用UDP以及UDP之上的自定义可靠传输机制;登录、支付、资源下载等对完整性要求更高的业务则可以使用TCP或HTTPS。
UDP本身不保证可靠、有序和重传,KCP就是在UDP等底层传输之上实现的一套可靠传输算法,通过序列号、ACK、超时重传、快速重传、选择性重传、窗口控制等机制补足可靠性。
KCP的核心优势不是"UDP天然比TCP快",而是它可以针对低延迟场景进行更激进的优化,例如缩短丢包检测和恢复时间、支持快速重传,并允许配置拥塞控制策略。代价是额外的带宽开销以及更低的网络公平性。
如果网络丢包严重,还可以结合FEC,通过冗余数据直接恢复部分丢失的数据,减少等待重传造成的延迟。
所以整个技术取舍可以概括为:
textTCP ↓ 可靠、有序、公平 ↓ 更适合通用可靠传输 UDP ↓ 低开销、低延迟、无内建可靠保证 ↓ 适合实时业务的底层传输 KCP ↓ UDP + 应用层可靠传输 ↓ 更积极的丢包恢复 ↓ 用带宽和复杂度换低延迟 FEC ↓ 用冗余数据直接恢复部分丢包 ↓ 进一步减少重传等待最终本质就是:实时业务不是不要可靠性,而是把"可靠性"从TCP的固定机制,变成可以由业务根据实时性、带宽、丢包率进行定制的机制。
记忆时只抓住 5 个词:
UDP打底 → KCP可靠 → 快速重传 → 可控拥塞 → FEC抗丢包
这 5 个词基本就能把整道题的主线讲出来。