一、UDP 协议的本质
UDP(用户数据报协议),是 TCP/IP 协议栈的传输层核心协议 ,和 TCP 同级,UDP 的设计理念是:「尽最大努力交付,牺牲可靠性换极致性能」。
1. UDP 原生的核心特性(无连接 + 面向报文)
这两个特性是 UDP「不可靠」的根本原因 ,也是 UDP「高性能」的核心根源
- 无连接 :通信双方无需建立连接、无需维护连接状态,客户端直接发数据包给服务端,服务端直接接收,没有三次握手、四次挥手;
- 面向报文 :UDP 把应用层的数据看作「一个完整的报文」,原样打包、原样发送、原样交付 ,发送方调用一次 send,接收方就调用一次 recv,不会拆分 / 合并数据,天然无粘包问题。
2. UDP 原生「不可靠」的具体体现
UDP 协议的内核实现中,没有任何可靠性保障机制 ,属于「裸奔式传输」,协议层面只负责把数据包发出去,至于对方收没收到、收到的对不对,一概不管。所有不可靠的现象,都是 UDP 的原生行为。
① 无确认应答机制
发送方发送 UDP 数据包后,不会收到接收方的任何「收到了」的确认消息,发送方完全不知道自己的数据包是否被对方成功接收。
② 无超时重传机制
发送方发现数据包丢失后,UDP 协议本身不会触发重传,数据包丢了就是丢了,没有补救措施。
③ 无序列号机制
UDP 数据包之间没有编号 ,接收方收到的数据包,无法判断数据包的发送顺序,会出现乱序问题(先发的包后到,后发的包先到)。
④ 无去重机制
因为网络抖动 / 路由转发,同一个 UDP 数据包可能被多次送达接收方,UDP 协议不会判断数据包是否重复,会把重复的包直接交给应用层。
⑤ 可能发生数据包丢失(最核心的不可靠点)
网络拥塞、链路故障、接收方缓冲区满、发送频率过快等,都会导致 UDP 数据包丢失,这是 UDP 最常见的问题,丢包率在公网中可能达到 1%~10%。
⑥ 无流量控制 & 无拥塞控制
- 流量控制:UDP 不会感知接收方的处理能力,如果发送方发的太快,接收方缓冲区满了,新来的数据包会被直接丢弃;
- 拥塞控制:UDP 不会感知网络拥塞,网络越卡,UDP 越会持续发数据包,只会加剧拥塞,导致更多丢包;
⑦ 存在数据包截断风险
UDP 有固定的报文大小限制(MTU,最大传输单元,一般是 1500 字节),如果应用层发送的数据包超过 MTU,IP 层会分片传输,只要有一个分片丢失,整个数据包就会失效,接收方无法重组,直接丢弃。
3. 既然 UDP 不可靠,为什么还存在并被广泛使用?
UDP 的核心价值:用「可靠性」换「极致的性能、低延迟、轻量级」,它的所有缺点都是「为优点做出的妥协」。
- 头部开销极小 :UDP 的头部只有 8 字节(源端口 + 目的端口 + 长度 + 校验和),TCP 的头部至少 20 字节,UDP 的传输开销远小于 TCP;
- 无连接开销:无需三次握手建立连接,无需维护连接状态,通信启动速度极快;
- 无延迟惩罚:没有 TCP 的拥塞控制导致的「慢启动、降速」,数据包能以最快速度到达对方;
- 支持广播 / 组播:UDP 是唯一支持广播(发给局域网所有主机)、组播(发给指定组的主机)的传输层协议,TCP 只支持单播;
- 面向报文无粘包:无需处理 TCP 的粘包 / 半包问题,应用层处理逻辑更简单;
- 资源占用少:服务器可以用一个端口接收来自数万客户端的 UDP 数据包,无需为每个客户端维护连接,内存 / CPU 占用极低。
二、UDP 可靠性的解决方案
UDP 协议本身无法被修改为可靠的,UDP 的可靠性,全部是在「应用层手动实现」的。
可靠 UDP = 「原生 UDP」 + 「应用层手动实现的可靠性保障机制」,本质是:把 TCP 协议的核心可靠性机制,在应用层复刻到 UDP 之上。
核心原则
实现可靠 UDP 的机制,不是越多越好,而是按需实现:
- 轻量可靠(游戏 / 音视频首选):只实现核心机制,兼顾可靠性和实时性;
- 完全可靠(文件传输):实现全部机制,接近 TCP 的可靠性,但保留 UDP 的部分优点;
实现的可靠性机制越多,UDP 的实时性越差,越接近 TCP;反之,实时性越好,可靠性越弱。
实现 UDP 可靠性的 6 个核心机制
机制 1:序列号 + 确认应答 (ACK)
作用
解决「丢包检测」+「乱序判断」+「重复判断」三大问题,是可靠 UDP 的基石。
实现逻辑
- 发送方:为每个发送的 UDP 数据包分配一个唯一递增的序列号(如 uint32_t seq),把序列号写入数据包的应用层头部;
- 接收方:收到数据包后,先检查序列号,然后立即向发送方发送一个ACK 应答包,ACK 包中携带「已成功接收的数据包的序列号」;
- 发送方:维护一个「待确认的序列号列表」,收到 ACK 包后,把对应序列号标记为「已确认」,证明该数据包被成功接收。
核心价值
- 丢包检测:发送方如果超时没收到某个序列号的 ACK,判定为丢包;
- 乱序判断:接收方通过序列号,能轻松判断数据包的发送顺序;
- 重复判断:接收方维护一个「最近接收的序列号窗口」,如果收到的序列号已经在窗口内,判定为重复包,直接丢弃。
机制 2:超时重传
作用
解决「数据包丢失」的补救问题,是可靠性的核心保障。
实现逻辑
- 发送方:为每个发送的、未被 ACK 的数据包,记录「发送时间戳」,并设置一个超时阈值(如 200ms);
- 超时判断:如果某个数据包的「当前时间 - 发送时间戳」> 超时阈值,且未收到 ACK,判定为丢包;
- 重传策略:立即重新发送该数据包,可设置「最大重传次数」(如 3 次),超过次数则判定为通信失败,避免无限重传。
动态超时阈值
固定超时阈值在复杂网络中不适用,最优方案是动态计算 RTT(往返时延),根据 RTT 动态调整超时阈值,和 TCP 的超时重传逻辑一致,能减少无效重传。
机制 3:去重处理
作用
解决「重复数据包」问题,避免应用层收到重复数据导致逻辑错误。
实现逻辑
基于「序列号」实现,有 2 种常用方案,都简单高效:
- 方案 1(推荐):接收方维护一个 最大已确认序列号,如果收到的数据包序列号 ≤ 该值,直接判定为重复包,丢弃;
- 方案 2:接收方维护一个 滑动窗口,记录最近接收的序列号,用于处理乱序场景下的重复包。
重复包的产生原因:网络抖动导致 ACK 包丢失,发送方触发重传,而原数据包其实已经被接收方收到。
机制 4:乱序重组
作用
解决「数据包乱序」问题,保证应用层收到的数据包是按发送顺序交付的,和 TCP 的字节流有序一致。
实现逻辑
- 接收方:维护一个 接收缓冲区(乱序队列),把收到的乱序数据包,按序列号的大小存入缓冲区;
- 有序交付:当接收方收到「连续的、无缺失的序列号数据包」时,才把这些数据包按顺序交给应用层;
- 丢弃过期:如果某个序列号的数据包超时未收到,且后续数据包已经到达,可选择丢弃该窗口的乱序包(实时场景)或等待(可靠场景)。
实时对战场景(如 MOBA、吃鸡),可以放弃乱序重组,只处理最新的数据包,牺牲少量有序性换极致实时性,这是游戏 UDP 的核心优化思路。
机制 5:流量控制
作用
解决「接收方处理能力不足」导致的丢包问题,避免发送方发的太快,接收方缓冲区满了丢包。
实现逻辑(轻量级,UDP 首选,无需像 TCP 复杂)
- 接收方:在 ACK 包中,携带「自己的剩余缓冲区大小」或「最大可接收的数据包数量」;
- 发送方:根据接收方的反馈,动态调整发送速率,如果接收方缓冲区不足,就暂停发送或降低发送频率。
UDP 的流量控制只需要「轻量级反馈」即可,无需 TCP 的滑动窗口,避免过度设计导致实时性下降。
机制 6:拥塞控制
作用
解决「网络拥塞」导致的大量丢包问题,避免发送方在网络拥塞时持续发数据包,加剧拥塞。
实现逻辑
UDP 的拥塞控制是可选的 ,因为它会牺牲部分实时性,游戏 / 音视频场景一般不实现复杂拥塞控制,只做简单的「慢启动」:
- 通信初期,低速发送数据包,逐步提高发送速率;
- 如果检测到丢包率升高,就适当降低发送速率,缓解网络拥塞。
看场景,实时性优先的场景(游戏、音视频)不需要,可靠性优先的场景(文件传输)需要。
可选增强机制
- 应用层校验和:UDP 协议本身有校验和,但可以在应用层再增加一层 CRC 校验,防止数据包在传输中被篡改,保证数据完整性;
- 心跳保活:UDP 无连接,通过心跳包检测对方是否在线,避免向离线的对端持续发送数据包;
- 分片重组:在应用层实现数据包的分片和重组,解决 UDP 的 MTU 限制问题,支持大文件传输。
三、可靠 UDP 的两种实现方案
方案一:基于成熟开源库实现可靠 UDP
1. KCP 协议
- 定位:
KCP是一个基于 UDP 的轻量级可靠传输协议,由快手的程序员实现,专为游戏设计; - 核心特点:可靠性接近 TCP,延迟远低于 TCP,KCP 的官方测试:同等网络环境下,KCP 的传输延迟是 TCP 的 1/3,丢包率高的网络中,KCP 的表现碾压 TCP;
- 核心优势:实现简单(只有一个头文件 + 一个源文件)、无缝集成到现有 UDP 代码、支持拥塞控制、支持快速重传、支持流量控制;
- 适用场景:所有游戏实时通信场景 (王者荣耀、和平精英、原神的实时对战)、游戏服务器的帧同步 / 状态同步,这是你作为游戏开发的必学必用协议。
2. UDT 协议
- 定位:基于 UDP 的可靠传输协议,主打高速大数据传输;
- 核心特点:可靠性和 TCP 持平,吞吐量远高于 TCP,支持拥塞控制;
- 适用场景:UDP 文件传输、视频流传输、大数据同步,游戏开发中用的较少。
3. RUDP
- 定位:通用的可靠 UDP 协议,是 TCP 的简化版,实现了核心的可靠性机制;
- 核心特点:轻量级、易集成,性能介于 TCP 和 KCP 之间;
- 适用场景:物联网、小型实时通信项目。
方案二:业务层自研轻量级可靠 UDP
如果业务场景非常简单(如局域网通信、低并发、小数据包),可以自研,只实现序列号 + ACK + 超时重传 + 去重这 4 个核心机制,足够满足可靠性需求,代码量少,维护成本低。
四、TCP vs 可靠 UDP
TCP 是 「强可靠、低实时性」 的可靠传输;
可靠 UDP 是 「弱可靠 / 软可靠、高实时性」 的可靠传输。
实时性优先,选可靠 UDP/KCP;数据完整性优先,选 TCP
-
必须用 TCP 的场景:对数据完整性要求极高,允许一定延迟,丢包不可接受的业务。游戏内的账号登录、充值支付、道具购买、邮件收发、排行榜数据同步; 后端的文件传输、数据库同步、HTTP/HTTPS 请求、金融交易数据传输。
-
必须用可靠 UDP/KCP 的场景:对实时性要求极高,允许少量丢包,延迟不可接受的业务。游戏内的实时对战(走位、技能释放、攻击判定)、帧同步 / 状态同步、语音聊天; 音视频直播、视频会议、物联网传感器实时数据上报、广播 / 组播通信。
五、总结
- UDP 原生不可靠,根源是无连接、面向报文、无可靠性机制,优点是低延迟、轻量级、高吞吐;
- 可靠 UDP = 原生 UDP + 应用层实现的「序列号 + ACK + 超时重传 + 去重 + 乱序重组」;
- 开发中无需自研,首选KCP 协议实现可靠 UDP,游戏开发的绝对主流;
- TCP 是强可靠低实时,可靠 UDP 是软可靠高实时,选型看业务场景;
- 游戏开发中:登录 / 充值用 TCP,实时对战用 KCP/UDP,这是最优解。