fix(scale): 修复 UdpBroadcastSender 启动时 IP 为空导致广播失效

- UdpBroadcastSender 改为接收 ipProvider 函数替代静态 localIp 参数,每次广播时动态获取 IP
- IP 为空时跳过本次广播并等待下一周期重试,避免设备启动时网络未就绪导致广播携带空 IP
- ScaleServiceManager 更新调用方式,传入 lambda 动态获取 IP

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 10:01:26 +08:00
co-authored by Claude Sonnet 4.6
parent 12c6b5cf94
commit af737b910c
2 changed files with 13 additions and 6 deletions
@@ -128,9 +128,8 @@ object ScaleServiceManager {
if (role == DeviceRole.MASTER) {
startMasterServices(context, deviceId)
} else {
// 子设备:启动 UDP 广播,作为 mDNS 的兜底发现机制
val localIp = getLocalIp(context)
udpSender = UdpBroadcastSender(deviceId, localIp).also { it.start() }
// 子设备:启动 UDP 广播,作为 mDNS 的兜底发现机制;每次广播时动态获取 IP,避免启动时网络未就绪导致 IP 为空
udpSender = UdpBroadcastSender(deviceId = deviceId, ipProvider = { getLocalIp(context) }).also { it.start() }
}
}
@@ -13,10 +13,12 @@ import java.util.concurrent.TimeUnit
* UDP 广播发送器(子设备运行)
* 每隔固定间隔向局域网广播本机的 deviceId、IP、WebSocket 端口
* 作为 mDNS 的兜底发现机制,确保主设备能可靠发现子设备
*
* @param ipProvider 动态获取本机 IP 的函数,每次广播时调用;返回空字符串时跳过本次广播
*/
class UdpBroadcastSender(
private val deviceId: String,
private val localIp: String,
private val ipProvider: () -> String,
private val wsPort: Int = MdnsRegisterManager.WS_PORT
) {
@@ -43,12 +45,18 @@ class UdpBroadcastSender(
task = scheduler.scheduleWithFixedDelay({
sendBroadcast()
}, 0, INTERVAL_SEC, TimeUnit.SECONDS)
Log.d(TAG, "UDP 广播已启动, deviceId=$deviceId, ip=$localIp, port=$wsPort")
Log.d(TAG, "UDP 广播已启动, deviceId=$deviceId, port=$wsPort")
}
private fun sendBroadcast() {
try {
val payload = gson.toJson(Payload(deviceId, localIp, wsPort))
val ip = ipProvider()
// 网络未就绪时跳过本次广播,等待下一个周期重试
if (ip.isEmpty()) {
Log.d(TAG, "IP 未就绪,跳过本次广播")
return
}
val payload = gson.toJson(Payload(deviceId, ip, wsPort))
val data = payload.toByteArray(Charsets.UTF_8)
DatagramSocket().use { socket ->
socket.broadcast = true