面试题:游戏、直播为什么常用 UDP?KCP 是什么?为什么比 TCP 更适合低延迟场景?

面试题:游戏、直播为什么常用 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,通过冗余数据直接恢复部分丢失的数据,减少等待重传造成的延迟。

所以整个技术取舍可以概括为:

text 复制代码
TCP
  ↓
可靠、有序、公平
  ↓
更适合通用可靠传输

UDP
  ↓
低开销、低延迟、无内建可靠保证
  ↓
适合实时业务的底层传输

KCP
  ↓
UDP + 应用层可靠传输
  ↓
更积极的丢包恢复
  ↓
用带宽和复杂度换低延迟

FEC
  ↓
用冗余数据直接恢复部分丢包
  ↓
进一步减少重传等待

最终本质就是:实时业务不是不要可靠性,而是把"可靠性"从TCP的固定机制,变成可以由业务根据实时性、带宽、丢包率进行定制的机制。

记忆时只抓住 5 个词:

UDP打底 → KCP可靠 → 快速重传 → 可控拥塞 → FEC抗丢包

这 5 个词基本就能把整道题的主线讲出来。

相关推荐
勤劳X码农1 小时前
2026年游戏解说AI配音软件怎么选?
人工智能·游戏
神奇的小猴程序员1 小时前
游戏像素资产生成工具
游戏
阿钱真强道13 小时前
17 嵌入式操作系统 | uloop 事件循环:TCP 客户端
c语言·tcp/ip·tcp·事件循环·uloop
要吃这碗饭14 小时前
深入理解 TCP 协议:从三次握手到可靠传输
网络·网络协议·tcp/ip
bryant_meng16 小时前
【Game】Powerful——Pets(4.4)125~135
游戏·幻唐志·墨虎·贪狼·蚩尤武魂
大侠归来17 小时前
TCP/IP 网络编程:多播与广播
网络·tcp/ip·智能路由器
bryant_meng19 小时前
【Game】Powerful——Pets(4.3)75~115
游戏·幻唐志·瑶光·赤炎童子·罗刹女
阿钱真强道21 小时前
28 嵌入式操作系统 | 网关加 TCP 命令通道:粘包/半包怎么切
网络·网络协议·tcp/ip·粘包
郝学胜-神的一滴1 天前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建