第 24 章 / 共 51 章
卷三 · 协议开发

UDP 服务:无连接世界的最小驱动

UDP 没有连接、没有握手、没有顺序——XServer 对它的驱动也相应收敛到一个回调。心跳、发现协议、日志收集都是它的地盘。

本章导读

站位全书最短的一章——因为 UDP 在 XServer 里的面最小。重点在 24.3 的发送模型(发送完全自理)与 24.4 的平台细节(Windows 的 ICMP 坑)。

24.1 引入

UDP 的语义是"每个数据报自包含":没有连接状态、没有重传、没有顺序保证。XServer 的 udp 驱动忠实反映这个语义——bind 端口、把每个到达的数据报连同来源地址交给你,就结束了。会话概念(如果有)由应用在数据报内容里自己携带。

24.2 一个回调

EventDgram 与消息结构
static void EventDgram(XS_HostInfo* pHost, xnetudp* pUdp,
    const xnetudpmessage* pMsg)
{
    /* pMsg 字段(xrt_decl.h 原文):
     *   Remote : 来源地址(回调内借用)
     *   Data/Size : 负载与长度
     *   Flags : XNET_UDP_MESSAGE_TRUNCATED(截断标志)等
     *   Meta  : 数据报元信息 */
    if ( pMsg->Flags & XNET_UDP_MESSAGE_TRUNCATED ) {
        /* 报文超过接收缓冲被截断——按协议决定丢弃或记录 */
        return;
    }
    (void)xrtNetUdpSendTo(pUdp, &pMsg->Remote, "ack", 3);
}

刚才发生了什么:每个数据报触发一次回调;每个数据报都经监听槽位取当前代 lease——热重载期间数据报与旧代/新代的归属判断和 TCP 同样精确(reload_matrix 有 UDP 关闭对端的 burst 覆盖用例)。

24.3 发送模型

  • 发送完全由脚本自理:xrtNetUdpSendTo(pUdp, 目标地址, 数据, 长度)——可以回来源、也可以发给任意第三方地址(转发/通知场景)
  • 来源地址转换文本用 xrt 地址族工具(日志 / 调试用)
  • 一次发送就是一个数据报——应用层的分片与重组(如需要)自己定义
  • recv_limit 上限 65535(ch07)——单个数据报的天然上限

24.4 平台细节

一个值得知道的 Windows 行为:往一个已关闭的端口发 UDP,对端协议栈可能回 ICMP Port Unreachable,而 Windows 会把这个 ICMP 反馈成下一次收发的错误——表现为"发了一个无关地址后,自己的收发莫名失败"。XServer 对此做了 ICMP 重置隔离(版本记录中专门的本地补丁):ICMP 引发的重置被隔离处理,不误伤后续数据报。reload_matrix 的 UDP 用例专门覆盖了这个平台行为。

UDP 无 TLS(ch07 的约束)——需要加密的应用层方案(协议内置密钥协商 + 载荷加密)在 ch33/ch46 的 XTP2 实战里展开。

24.5 契约

  • 借用线:pMsg(含 Remote/Data)回调内有效——转发前拷贝需要保留的字段。
  • 发送线:一切发送经 xrtNetUdpSendTo 自理;数据报边界由 UDP 保证(内容完整性自己校验)。
  • 代际线:每报取当前代 lease——重载期间新报进新代,语义与 TCP 一致。

常见错误

在 UDP 上期待"连接"
症状
写出了依赖顺序与会话的协议,实测丢序/丢包后状态机错乱。
原因
UDP 不保证送达与顺序——会话与重传要么自己建(序列号 + ACK),要么换 TCP。
忽略 TRUNCATED 标志
症状
偶发处理了半截报文,校验失败难以复现。
原因
报文超过接收上限被截断时 Flags 会标出——不检查就会把残包当完整包处理。

编程练习

基础心跳应答器

收到 "PING" 回 "PONG";其他内容丢弃。

验收:自定义 UDP 客户端 100 次往返;统计丢包率(本机应为 0)。
进阶带序列号的可靠层

在应用层实现 seq + ACK + 重传的迷你可靠协议(窗口为 1 即可)。

验收:用 tc netem 或随机丢弃(脚本模拟)注入 10% 丢包仍能完整传文件。
挑战服务发现

实现组播/广播发现:客户端广播 DISCOVER,服务端单播应答自己的 HTTP 端口。

验收:多实例场景客户端能枚举全部实例且无重复。

小结

要点结论
回调面仅 EventDgram;每报带来源地址与标志
发送xrtNetUdpSendTo 自理;可回发可转发任意地址
限额recv_limit ≤65535;TRUNCATED 标志必须检查
平台Windows ICMP 重置已隔离;可靠性与顺序应用自建
代际每报取当前代 lease,重载语义与 TCP 一致
本章涉及的 API 参考
xrt 延伸阅读