88 lines
4.4 KiB
Markdown
88 lines
4.4 KiB
Markdown
# 局域网服务发现:组播叠加设计
|
|
|
|
日期: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`
|
|
|
|
新增:
|
|
|
|
```csharp
|
|
public const string MulticastGroup = "239.192.48.92";
|
|
```
|
|
|
|
### 2. 服务端 `Server\Gateway\DevDiscoveryResponder.cs`
|
|
|
|
构造函数中,绑定 `0.0.0.0:48923` 后,枚举本机所有 Up 状态、非 Loopback 的 IPv4 网卡,对每块网卡执行:
|
|
|
|
```csharp
|
|
_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 = true`、`MulticastTimeToLive = 1`,向 `239.192.48.92:48923` 发查询,断言收到合法回复(验证响应器 join 组播组 + 组播收包路径)。
|
|
- 现有单播/广播测试不动。
|
|
|
|
## 验收标准
|
|
|
|
1. 服务端/客户端单元测试通过。
|
|
2. 编辑器同机自测:发现日志中出现组播目标,发现成功。
|
|
3. 真机同网段:发现成功(组播或广播任一路径)。
|
|
4. 真机跨网段实测:若组播路径通 → 后续任务删除 `DevExtraProbeIps` 写死 IP;若不通 → 保留写死 IP,评估"探测 IP 可配置化"方案。
|
|
|
|
## 风险
|
|
|
|
- **组播路由未验证**:公司路由器可能未开 PIM/IGMP Proxy,组播出不了网段。缓解:纯增量设计,失败无损现状。
|
|
- **部分 Android WiFi 驱动丢组播发包**:概率低(丢的主要是收方向),且广播路径仍在。
|