第 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 延伸阅读
- xrt 参考 · udp — 数据报收发与地址族工具全集