# 移动端局域网服务发现（UDP）对接文档

## 1. 架构概述
本系统在局域网环境下采用 **UDP 广播 (UDP Broadcast)** 机制进行后端的自动寻址。
移动端（Android / iOS）无需让用户手动输入后端 IP，只需向局域网发送特定“暗号”（Magic Word），后端的网络代理程序收到后会自动回复当前应连接的局域网 IP 和 HTTP 服务端口。

移动端获取到动态 IP 后，将其拼接为全局 `Base URL`，随后所有业务网络请求（HTTP/RESTful）均通过此 URL 进行。

当前版本服务端只返回 **一个自动选择出的 IP**。在多网卡环境下，服务端会优先根据本次请求来源选择回包 IP，而不是固定挑一个 `192.168.x.x`。

## 2. 网络通信协议标准
* **通信协议**: UDP (User Datagram Protocol)
* **目标广播地址**: `255.255.255.255`
* **目标目标端口**: `8888`
* **字符编码**: `UTF-8`
* **寻址超时时间**: `3000 ms` (3秒)

### 2.1 请求数据报文 (Client -> Server)
客户端通过 UDP 发送纯文本字符串（暗号），**不需要**携带换行符或 JSON 格式。

**不同项目的暗号对照表：**
* 通用基础版 (Standard Edition): `DISCOVER_STANDARD_EDITION`
* 高级维护版 (Advanced Edition): `DISCOVER_ADVANCED_EDITION`
* 内部测试版 (Beta Edition - 仅供开发调试): `DISCOVER_BETA_EDITION`

### 2.2 响应数据报文 (Server -> Client)
若局域网内存在对应的后端服务，客户端将收到格式固定的纯文本字符串，格式为：
`SERVER_IP:{局域网IP}:{HTTP端口}`

**报文示例：**
`SERVER_IP:192.168.1.105:8000`

客户端需解析此字符串，提取 IP 和端口，组合成标准 HTTP 地址：`http://192.168.1.105:8000`。

## 3. 移动端标准连接策略（状态机）
移动端在处理服务寻址时，必须严格按照以下优先级策略执行，以保证启动速度和用户体验：

1. **缓存优先（Cache-First）**:
   * App 启动时，优先读取本地缓存（SharedPreferences/UserDefaults）中上一次成功连接的 `Base URL`。
   * 向该 URL 发起一个轻量级 HTTP 探测请求（如 `GET /ping`，设置 1.5 秒超时）。若 HTTP 200 OK，直接进入主界面。若超时或失败，进入第 2 步。
2. **UDP 广播寻址（Discovery）**:
   * 弹出“正在寻找设备”的 Loading 提示。
   * 开启 UDP Socket 向 `255.255.255.255:8888` 发送对应的项目暗号。
   * 阻塞监听 UDP 回复，最多等待 3 秒。
   * 若收到格式正确的 `SERVER_IP:...` 回复，保存新 URL 至本地缓存，关闭 Loading，进入主界面。若 3 秒后无响应，进入第 3 步。
3. **人工干预兜底（Fallback）**:
   * 提示用户“未发现局域网设备（可能是跨网段或网络隔离）”。
   * 提供【手动输入 IP】和【扫码连接】界面。扫码内容即为后端电脑屏幕上显示的完整 `Base URL`。

## 4. 平台开发实现指南（AI 提示词参考）

你可以直接将以下提示词发给 AI 来生成双端的网络层代码。

### 🤖 针对 Android 端的 AI 开发指令：
> “请使用 Kotlin 和 Coroutines 帮我实现一个 `UdpDiscoveryClient` 单例。
> 要求：
> 1. 使用 `DatagramSocket` 向可配置的广播地址和 UDP 端口发送广播报文，默认是 `255.255.255.255:8888`，报文内容是 UTF-8 字符串参数 `magicWord`。
> 2. 设置 `soTimeout` 为可配置值，默认 3000ms。
> 3. 监听回复，若收到以可配置前缀 `responsePrefix` 开头的字符串，默认前缀是 `SERVER_IP:`，解析出后面的 IP 和端口，拼接成 `http://IP:PORT` 的格式并返回。
> 4. 若超时或发生异常，捕获后返回 null。
> 5. 整个过程必须在 `Dispatchers.IO` 线程中挂起执行，不可阻塞主线程。
> 6. 对外暴露 `magicWord`、`timeoutMs`、`targetPort`、`broadcastIp`、`responsePrefix` 这几个参数，方便后续迁移到其他 Android 项目。
> 7. 额外提供一个 `discoverFromJava(...)` 静态桥接方法，方便 Java 页面直接调用。”

### 🤖 针对 iOS 端的 AI 开发指令：
> “请使用 Swift 帮我实现一个 `UDPDiscoveryService` 类。
> 要求：
> 1. 推荐使用 Apple 原生的 `Network` 框架 (`NWConnection` / `NWEndpoint`)，或者轻量级的第三方库 `GCDAsyncUdpSocket`。
> 2. 需要向广播地址 `255.255.255.255` 的 `8888` 端口发送 UDP 报文（参数 `magicWord` 转为 UTF-8 Data）。
> 3. 注意开启 UDP 的广播权限（如 `NWParameters.udp` 配置中允许 broadcast）。
> 4. 设置监听回调，最多等待 3 秒（可使用 `DispatchWorkItem` 或 `async/await` 的 Task 控制超时）。
> 5. 若收到以 `SERVER_IP:` 开头的报文，解析并返回拼接好的 `http://IP:PORT` 格式字符串。若超时或失败，返回 nil 或抛出自定义 Error。”

---
