fix: 点击连接按钮后立即启动心跳线程,不再等待数据包接收

ProtocolClient.connect() 现在立即启动心跳循环(1Hz),而不是
等到 receiveLoop 首次收到数据包后才启动。心跳在 CONNECTING 和
CONNECTED 状态下均正常运行,确保连接建立过程中机器人能持续收到
心跳包。

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-07-18 14:58:19 +08:00
parent fbc3f1529f
commit d4db91235b
2 changed files with 13 additions and 7 deletions
@@ -92,7 +92,8 @@ class ProtocolClient(
* 2. 启动接收/发送协程
* 3. 发送订阅请求
* 4. 启动断线检测(CONNECTING 5s / CONNECTED 3s 无数据 → TIMEOUT
* 5. 首次收到有效数据包后标记已连接,并启动心跳 1Hz(在接收循环中处理
* 5. 启动心跳 1Hz(立即发送,覆盖 CONNECTING 和 CONNECTED 状态
* 6. 首次收到有效数据包后标记已连接
*/
fun connect() {
if (_state.value != State.DISCONNECTED && _state.value != State.ERROR) return
@@ -136,6 +137,11 @@ class ProtocolClient(
timeoutJob = scope.launch {
timeoutCheckLoop()
}
// 启动心跳(立即开始,覆盖 CONNECTING 和 CONNECTED 状态)
heartbeatJob = scope.launch(Dispatchers.IO) {
heartbeatLoop(sock, address)
}
} catch (e: Exception) {
_state.value = State.ERROR
closeSocket()
@@ -227,12 +233,9 @@ class ProtocolClient(
_statusReport.tryEmit(report)
}
// 首次收到有效数据包:标记已连接,启动心跳
// 首次收到有效数据包:标记已连接
if (_state.value == State.CONNECTING) {
_state.value = State.CONNECTED
heartbeatJob = scope.launch(Dispatchers.IO) {
heartbeatLoop(sock, remoteAddress!!)
}
}
} catch (_: SocketTimeoutException) {
// 超时正常,继续循环
@@ -246,9 +249,11 @@ class ProtocolClient(
}
}
/** 心跳循环(1 Hz */
/** 心跳循环(1 Hz—— 在 CONNECTING 和 CONNECTED 状态下运行 */
private suspend fun CoroutineScope.heartbeatLoop(sock: DatagramSocket, address: InetAddress) {
while (isActive && _state.value == State.CONNECTED) {
while (isActive &&
(_state.value == State.CONNECTING || _state.value == State.CONNECTED)
) {
try {
val json = ControlCommands.heartbeat()
val packet = encoder.encode(json)