Files
AIC-Project/docs/superpowers/specs/2026-07-06-multicast-discovery-design.md
T
2026-07-10 10:24:29 +08:00

4.4 KiB

局域网服务发现:组播叠加设计

日期:2026-07-06 状态:已批准(方案 A)

背景与问题

真机内网联调依赖 UDP 发现机制找到开发机上的网关/CDN 地址。当前客户端探测目标为: 255.255.255.255 + 127.0.0.1 + 各网卡子网定向广播 + 写死的开发机 IP 192.168.130.40

定向广播默认不被路由器转发(RFC 2644,已实测不通),跨网段场景只能靠写死 IP 兜底——换机器/换网段就要改代码,不通用。

目标

  • 新增组播探测路径,使发现请求有机会跨网段到达开发机(取决于路由器是否开启组播路由,当前网络环境未验证)。
  • 纯增量改动:现有广播/loopback/写死 IP 路径全部保留,任何一条路通即发现成功;组播不通也不比现状差。

非目标

  • 不移除写死 IP(实测组播跨网段可行后再删)。
  • 不做探测 IP 可配置化(若组播实测失败,作为后续备选方案)。
  • 不改发现协议本身(magic "XWDL"、端口 48923、编解码格式均不变)。

关键技术决策

决策 取值 理由
组播组地址 239.192.48.92 239.192.0.0/14 为组织本地范围(RFC 2365),专为跨子网管理域设计;239.255.0.0/16 是本地范围,路由器可能限制其跨网段
端口 48923(复用现有) 服务端同一 socket 可同时收单播/广播/组播,零额外监听
客户端组播 TTL 8 组播默认 TTL=1 出不了本网段;8 足够覆盖内网多级路由,又不至于扩散过远
Android MulticastLock 不需要 客户端只组播、单播回复;MulticastLock 只影响收组播

改动清单

1. 协议常量 XWorld.Framework.Protocol.DevDiscovery

新增:

public const string MulticastGroup = "239.192.48.92";

2. 服务端 Server\Gateway\DevDiscoveryResponder.cs

构造函数中,绑定 0.0.0.0:48923 后,枚举本机所有 Up 状态、非 Loopback 的 IPv4 网卡,对每块网卡执行:

_udp.JoinMulticastGroup(groupAddr, nicIPv4Addr);
  • 默认 JoinMulticastGroup(group) 只加入默认网卡,多网卡开发机(有线+无线/虚拟网卡)会漏收,故须逐网卡 join。
  • 逐网卡 try/catch,任何一块失败不中断其余(与客户端 GetDirectedBroadcasts 的容错风格一致)。
  • 收包与回复逻辑零改动:组播查询的 RemoteEndPoint 是发送方单播地址,现有单播回复天然可用。

3. 客户端热更层 Client\Assets\Script\xmain\MiniGame\DevServerDiscovery.cs

  • socket 初始化后设置 MulticastTimeToLive = 8
  • 组播端点不加入 targets 通用列表(避免只走默认路由网卡),而是在每轮重发中单独处理:逐 Up 状态 IPv4 网卡设置 IP_MULTICAST_IF(SocketOptionName.MulticastInterface,值为网卡 IPv4 地址字节)后向 239.192.48.92:48923 发一次,逐网卡 try/catch。
    • 手机通常单网卡,此逻辑主要覆盖编辑器/PC 多网卡场景。
  • 现有 targets(广播、loopback、定向广播、DevExtraProbeIps)全部不动;DevExtraProbeIps 注释更新:组播跨网段实测通过后可删。

4. 客户端底包 Client\Assets\Base\LocalCdnDiscovery.cs

与热更层同步:内联 MulticastGroup 常量(Base 程序集不能引用热更程序集,沿用现有"改协议时两边须同步"约定),发送逻辑同第 3 条。

错误处理

join / 设组播网卡 / 发送失败全部静默吞掉——发现机制是"多路齐发、谁通算谁",单路失败不影响整体,与现有代码风格一致。

测试

Server\Gateway.Tests\DevDiscoveryResponderTests.cs 新增一条:

  • 客户端测试 socket 设置 MulticastLoopback = trueMulticastTimeToLive = 1,向 239.192.48.92:48923 发查询,断言收到合法回复(验证响应器 join 组播组 + 组播收包路径)。
  • 现有单播/广播测试不动。

验收标准

  1. 服务端/客户端单元测试通过。
  2. 编辑器同机自测:发现日志中出现组播目标,发现成功。
  3. 真机同网段:发现成功(组播或广播任一路径)。
  4. 真机跨网段实测:若组播路径通 → 后续任务删除 DevExtraProbeIps 写死 IP;若不通 → 保留写死 IP,评估"探测 IP 可配置化"方案。

风险

  • 组播路由未验证:公司路由器可能未开 PIM/IGMP Proxy,组播出不了网段。缓解:纯增量设计,失败无损现状。
  • 部分 Android WiFi 驱动丢组播发包:概率低(丢的主要是收方向),且广播路径仍在。