UDP可靠性传输指南:从基础机制到KCP协议核心解析
一.可靠传输的核心原理:5 大基础机制
数据传输的过程中,需要满足三个最基本条件:不丢失,不重复,按顺序
通过五个核心机制来满足这三个条件:
ACK 机制:接收方收到数据后,给发送方回一个确认包(ACK),告诉发送方我收到数据;如果发送方没收到ACK,则说明数据丢失了,需要重传
重传机制:发送方发完数据后启动定时器,若超时没收到ACK,就重新发送数据;重传策略中的:超时多久重传、重传几次,决定了效率。
序号机制:给每个数据包编上唯一序号,如 1、2、3,接收方通过序号判断数据有没有丢、有没有重,如收到 1、3,说明2丢了,收到 2、2,说明重复了。
重排机制:网络传输可能乱序,接收方通过序号把乱序的数据包重新排回正确顺序,再交给应用层。
窗口机制:发送方不能无限制发数据,否则接收方处理不过来,或网络堵了,通过窗口大小控制一次最多发多少数据,窗口机制分两种:流量控制,针对接收方缓存,拥塞控制,针对网络。
二.UDP与TCP:为什么选择可靠UDP
UDP与TCP的区别在于,TCP面向连接传输可靠,但传输速度慢,不适合某些对延迟要求低的场景,UDP延迟低,轻量,但不可靠,会丢包,传输的数据会乱序,不能直接使用,所以在这样的基础上,加入可靠传输机制,既降低传输延迟,也提升传输速率,这就是KCP协议
对比维度 | UDP | TCP |
---|---|---|
是否连接 | 无连接(发数据前不用握手) | 面向连接(三次握手建立连接) |
是否可靠 | 不可靠,无流量 / 拥塞控制 | 可靠,有流量 / 拥塞控制 |
连接对象 | 支持一对多、多对多 | 只能一对一 |
传输方式 | 面向报文,不拆分,合并传输 | 面向字节流,拆分成段传输 |
首部开销 | 8字节 | 最小 20 字节,最大 60 字节 |
适用场景 | 实时场景:IP 电话、视频会议、游戏,关注传输速度 | 可靠场景:文件传输、网页加载,关注传输准确度 |
三.可靠传输的底层支撑:ARQ 协议三模式
ARQ自动重传请求是实现可靠传输的核心协议,文档分了3种模式,它们的差异主要在:滑动窗口的使用 和 丢包后的重传策略,直接决定了传输效率
3.1停等式 ARQ:最简单的可靠传输,效率低
工作原理:发送方发一个数据包->停下来等接收方回发的ACK->收到ACK再发下一个;如果超时没收到ACK,重传这个包
优点:逻辑简单,不需要复杂的窗口管理
缺点:等待时间太长,效率极低,传输距离远时发一个包也需较长时间,只适合数据量小、对效率要求低的场景
3.2回退n帧ARQ(GBN):连续发包提升效率,但丢包后浪费大
为了解决停等式的等待浪费,GBN允许发送方连续发多个包,不用等每个包的ACK,但丢包后要回退重传后面所有包
核心机制:滑动窗口
发送方有一个发送窗口,比如大小为5,可以连续发窗口内的5个包1、2、3、4、5,不用等 ACK;接收方有一个 接收窗口大小为1,只能按序接收,只接收当前期望的序号,先等 1,收到1 才等2,没收到1就丢所有后续包
丢包处理:比如包2丢了,接收方会丢3、4、5,只给1回 ACK;发送方超时后,会重传 2、3、4、5,从丢包的序号开始,回退 n 帧重传
优点:比停等式快很多,连续发包减少等待
缺点:丢包后重传太多,如果窗口大、丢包早,要重传很多包,浪费带宽
3.3选择性重传ARQ(SR):高效可靠的终极选择(附窗口机制解析)
GBN的问题是丢一个包要重传一堆,SR协议优化为只重传丢的那个包,效率最高
核心机制:双滑动窗口:发送 + 接收都有窗口,且大小相等
发送方窗口:比如大小为5,可连续发5个包,每个包有独立定时器
接收方窗口:大小为5,能接收窗口内的乱序包,比如期望1,收到3会缓存,等1、2到了再按序交给应用层
丢包处理:比如包2丢了,接收方会给1、3、4、5回ACK,告诉发送方1、3、4、5收到了,只缺少2;发送方看到2 没 ACK,3、4、5 有ACK,只重传 2,不用重传 3、4、5
优点:最高效,只重传丢的包,带宽浪费少
缺点:逻辑复杂,需要缓存乱序包、每个包独立计时,接收方需要更大的缓存
四.UDP可靠传输的最优解:KCP协议详解
KCP协议是基于UDP实现的可靠传输中间件,设计目标是在实时性场景中突破TCP的延迟问题,以10%~20%的带宽浪费为代价,换取比TCP快30%~40%的传输速度
4.1KCP的6个核心优化破解TCP延迟问题
TCP 的延迟问题主要在于:重传策略、ACK 机制、流控逻辑方面,针对这些方面进行以下优化
(1)RTO增长系数
TCP的RTO(重传超时时间)采用超时后xx2的策略,连续丢包时延迟会急速膨胀,如RTO初始为100ms,丢3次包后会变成 800ms,严重影响实时性;KCP在快速模式下将RTO增长系数调整为 x1.5:同样以100ms初始RTO为例,丢3次包后RTO仅为450ms,远低于TCP的 800ms,大幅缩短重传等待时间
(2)重传策略
TCP 丢包时,会从丢包序号开始,重传后续所有已发送但未确认的数据包,例如丢了2号包,会连3、4、5号包一起重传,造成大量带宽浪费,KCP 采用选择性重传:仅重传真正丢失的数据包如丢了2号包,只重传2号,避免不必要的重传,在窗口较大、丢包率较高的场景中,效率优势更明显
(3)快速重传
TCP判断丢包依赖RTO 超时或收到 3 个重复 ACK,前者等待时间长,后者对乱序敏感。KCP 的快速重传逻辑更灵活:发送方发送1、2、3、4、5号包后,若收到 ACK 1、3、4、5,会通过 ACK跨越次数判断丢包,收到ACK3时,知道2号包被跳过1次,收到ACK4时,知道2号被跳过2次,此时无需等 RTO,直接重传2号包,将丢包检测时间从百毫秒级压缩到毫秒级
(4)ACK 机制
TCP 为充分利用带宽,默认延迟发送 ACK,通常延迟 200ms 左右,导致RTT(往返时延)计算值偏大,进而使 RTO 偏大,丢包时重传更慢;KCP允许手动调节ACK延迟:实时场景可关闭延迟 ACK,收到数据立即回 ACK,让RTT计算更精准;非实时场景可开启延迟,平衡带宽利用率,灵活适配不同业务需求
(5)确认模型
传统 ARQ 协议的确认模型只有两种:
UNA:仅告知某序号前的包已收到,丢包时需全部重传
ACK:仅告知某序号的包已收到,单独发ACK包开销高
KCP采用UNA+ACK 结合:除单独的ACK包外,所有数据包包头都携带UNA信息,告知对方 已收到的最大连续序号,既避免TCP的 全部重传,又减少单独ACK的带宽开销,兼顾可靠性与效率。
(6)流控逻辑
TCP 的拥塞控制采用公平退让策略,即使网络轻微拥塞,也会大幅减小发送窗口,导致实时场景的传输速度骤降
KCP 提供非退让流控选项:正常模式下与TCP一致,按发送缓存、接收窗口、拥塞状态控制发送速度;实时性要求极高的场景,可配置跳过后两步,仅按发送缓存+接收窗口控制,以牺牲部分带宽公平性为代价,确保即使在网络波动时,也能保持流畅传输。
4.2KCP关键概念
conv:连接号,UDP无连接,用conv唯一标识客户端,确保数据归属正确
MTU:最大传输单元,默认1400 字节,避免IP分片,KCP会按MTU拆分应用层数据
RTO:重传超时时间,发送方超时未收ACK则重传,KCP可手动调整最小RTO,默认100ms
cwnd:拥塞窗口,按网络拥塞程度动态调整,控制发送方最多能发的数据包数量
rwnd:接收窗口,接收方告知发送方还能接收的数据包数量,避免接收方缓存溢出
snd_queue:待发送队列,应用层数据先存这里,等待KCP调度到发送缓存
snd_buf:发送缓存,存已发送未确认的数据包,超时后从这里取包重传
snd_nxt/snd_una:snd_nxt是下一个要发的序号,snd_una是下一个待确认的序号,标记传输进度
4.3KCP 使用流程
KCP 需按固定流程调用 API
1.创建KCP对象:调用ikcpcb *kcp = ikcpcb_create(conv, user),conv是唯一连接号,user存自定义数据
2.绑定UDP发送回调:设置kcp->output = udp_output,udp_output内部调用UDP的sendto,负责底层发送
3.定期调度update:在线程/定时器中每5~10ms调用ikcp_update,驱动KCP超时检测、重传
4.处理UDP接收数据:UDP用recvfrom收数据后,调用ikcp_input(kcp, 接收缓存, 接收长度),让KCP解析包类型
5.收发应用层数据:发送用ikcp_send(kcp, 数据缓存, 数据长度),接收用ikcp_recv(kcp, 接收缓存, 最大长度)
4.5 KCP 核心机制:发送 / 接收流程与窗口控制
(1)发送流程:从应用数据到 UDP 包
数据分片:应用层数据按MTU拆分,每个分片加24字节KCP头
队列调度:分片先入snd_queue,ikcp_flush将分片移到snd_buf,移动数量取min(发送窗口, 接收窗口, 拥塞窗口)
UDP 发送:ikcp_flush调用output回调发数据,每个分片启动定时器,超时未收ACK则重传
(2)接收流程:从 UDP 包到应用数据
包解析:ikcp_input解析KCP头,验证conv,按cmd处理
数据包(PUSH):乱序包存rcv_buf,按序包移到rcv_queue
确认包(ACK):标记snd_buf中对应包为已确认,更新snd_una
数据交付:应用层调用ikcp_recv,从rcv_queue读按序数据,分片自动拼接
(3)窗口控制:
发送窗口:取min(发送方最大窗口, 接收窗口, 拥塞窗口),避免发太快
接收窗口:默认 32,应用层读数据后窗口增大;若窗口为0,发送方发窗口询问包,接收方回复当前窗口
4.6 KCP 配置模式
KCP通过ikcp_nodelay等函数配置,如下:
默认模式:ikcp_nodelay(kcp, 0, 10, 0, 0),需稳定可靠,对延迟要求低
普通模式:ikcp_nodelay(kcp, 0, 10, 0, 1),需速度,可接受少量带宽浪费
极速模式:ikcp_nodelay(kcp, 2, 10, 2, 1);kcp->rx_minrto = 10;游戏、音视频等低延迟场景