## 心跳机制 * 边缘主机通过心跳机制来判断主机是否存活(解决弱网环境下websocket链接会经常断开的问题) * 边缘主机定期发送 UDP 心跳包,服务端按照 `iot_host` 的心跳检测周期判断是否有收到心跳包。 * 如果 UDP 心跳丢失但 SSL channel 仍然存在,服务端不会把 host 标记为离线。 * 如果 UDP 心跳丢失且 SSL channel 也不存在,服务端会把 host 标记为离线。 ### udp服务器 * 端口: 18080 ### 心跳包格式 旧格式 `<>` 已不再接受。 当前心跳包格式: ```erlang << Version:8, UuidLen:16, UUID:UuidLen/binary, Timestamp:64/unsigned-big, Nonce:16/binary, Mac:32/binary >> ``` 字段说明: | 字段 | 说明 | | --- | --- | | `Version` | 当前固定为 `1`。 | | `UuidLen` | `UUID` 的字节数。 | | `UUID` | efka 对应的 host UUID。 | | `Timestamp` | 秒级 Unix 时间戳。服务端只接受 120 秒时间窗内的心跳。 | | `Nonce` | 16 字节随机数,必须加入 HMAC payload,使同一秒内多次心跳的 Mac 不同。当前服务端不保存 nonce。 | | `Mac` | HMAC-SHA256 结果,32 字节。 | `Mac` 的计算内容为前面所有字段: ```erlang Payload = <>, Mac = crypto:mac(hmac, sha256, HeartbeatSecret, Payload) ``` 服务端在 `efka_client_store:verify_heartbeat/4` 中校验时间窗和 HMAC。`HeartbeatSecret` 使用 `SHA256(Token)`,其中 `Token` 和 TLS 鉴权使用同一个 auth token。`iot` 侧只保存派生后的 `heartbeat_secret`,不保存明文 token。