MQTT + UDP 混合通訊協議文件
基於程式碼實作整理的 MQTT + UDP 混合通訊協議文件,概述裝置端與伺服器之間如何透過 MQTT 進行控制訊息傳輸,透過 UDP 進行音訊資料傳輸的互動方式。
1. 協議概覽
本協議採用混合傳輸方式:
- MQTT:用於控制訊息、狀態同步、JSON 資料交換
- UDP:用於即時音訊資料傳輸,支援加密
1.1 協議特點
- 雙通道設計:控制與資料分離,確保即時性
- 加密傳輸:UDP 音訊資料使用 AES-CTR 加密
- 序列號保護:防止資料包重放和亂序
- 自動重連:MQTT 連線斷開時自動重連
2. 總體流程概覽
sequenceDiagram participant Device as ESP32 裝置 participant MQTT as MQTT 伺服器 participant UDP as UDP 伺服器 Note over Device, UDP: 1. 建立 MQTT 連線 Device->>MQTT: MQTT Connect MQTT->>Device: Connected Note over Device, UDP: 2. 請求音訊通道 Device->>MQTT: Hello Message (type: "hello", transport: "udp") MQTT->>Device: Hello Response (UDP 連線資訊 + 加密金鑰) Note over Device, UDP: 3. 建立 UDP 連線 Device->>UDP: UDP Connect UDP->>Device: Connected Note over Device, UDP: 4. 音訊資料傳輸 loop 音訊串流傳輸 Device->>UDP: 加密音訊資料 (Opus) UDP->>Device: 加密音訊資料 (Opus) end Note over Device, UDP: 5. 控制訊息交換 par 控制訊息 Device->>MQTT: Listen/TTS/MCP 訊息 MQTT->>Device: STT/TTS/MCP 回應 end Note over Device, UDP: 6. 關閉連線 Device->>MQTT: Goodbye Message Device->>UDP: Disconnect
3. MQTT 控制通道
3.1 連線建立
裝置透過 MQTT 連接到伺服器,連線參數包括:
- Endpoint:MQTT 伺服器地址和埠號
- Client ID:裝置唯一識別符
- Username/Password:認證憑證
- Keep Alive:心跳間隔(預設240秒)
3.2 Hello 訊息交換
3.2.1 裝置端傳送 Hello
{
"type": "hello",
"version": 3,
"transport": "udp",
"features": {
"mcp": true
},
"audio_params": {
"format": "opus",
"sample_rate": 16000,
"channels": 1,
"frame_duration": 60
}
}
3.2.2 伺服器回應 Hello
{
"type": "hello",
"transport": "udp",
"session_id": "xxx",
"audio_params": {
"format": "opus",
"sample_rate": 24000,
"channels": 1,
"frame_duration": 60
},
"udp": {
"server": "192.168.1.100",
"port": 8888,
"key": "0123456789ABCDEF0123456789ABCDEF",
"nonce": "0123456789ABCDEF0123456789ABCDEF"
}
}
欄位說明:
udp.server
:UDP 伺服器地址udp.port
:UDP 伺服器埠號udp.key
:AES 加密金鑰(十六進位字串)udp.nonce
:AES 加密隨機數(十六進位字串)
3.3 JSON 訊息類型
3.3.1 裝置端→伺服器
Listen 訊息
{
"session_id": "xxx",
"type": "listen",
"state": "start",
"mode": "manual"
}
Abort 訊息
{
"session_id": "xxx",
"type": "abort",
"reason": "wake_word_detected"
}
MCP 訊息
{
"session_id": "xxx",
"type": "mcp",
"payload": {
"jsonrpc": "2.0",
"id": 1,
"result": {...}
}
}
Goodbye 訊息
{
"session_id": "xxx",
"type": "goodbye"
}
3.3.2 伺服器→裝置端
支援的訊息類型與 WebSocket 協議一致,包括:
- STT:語音辨識結果
- TTS:語音合成控制
- LLM:情感表達控制
- MCP:物聯網控制
- System:系統控制
- Custom:自訂訊息(可選)
4. UDP 音訊通道
4.1 連線建立
裝置收到 MQTT Hello 回應後,使用其中的 UDP 連線資訊建立音訊通道:
- 解析 UDP 伺服器地址和埠號
- 解析加密金鑰和隨機數
- 初始化 AES-CTR 加密上下文
- 建立 UDP 連線
4.2 音訊資料格式
4.2.1 加密音訊包結構
|type 1byte|flags 1byte|payload_len 2bytes|ssrc 4bytes|timestamp 4bytes|sequence 4bytes|
|payload payload_len bytes|
欄位說明:
type
:資料包類型,固定為 0x01flags
:標誌位,目前未使用payload_len
:負載長度(網路位元組序)ssrc
:同步來源識別符timestamp
:時間戳記(網路位元組序)sequence
:序列號(網路位元組序)payload
:加密的 Opus 音訊資料
4.2.2 加密演算法
使用 AES-CTR 模式加密:
- 金鑰:128位元,由伺服器提供
- 隨機數:128位元,由伺服器提供
- 計數器:包含時間戳記和序列號資訊
4.3 序列號管理
- 傳送端:
local_sequence_
單調遞增 - 接收端:
remote_sequence_
驗證連續性 - 防重放:拒絕序列號小於期望值的資料包
- 容錯處理:允許輕微的序列號跳躍,記錄警告
4.4 錯誤處理
- 解密失敗:記錄錯誤,丟棄資料包
- 序列號異常:記錄警告,但仍處理資料包
- 資料包格式錯誤:記錄錯誤,丟棄資料包
5. 狀態管理
5.1 連線狀態
stateDiagram direction TB [*] --> Disconnected Disconnected --> MqttConnecting: StartMqttClient() MqttConnecting --> MqttConnected: MQTT Connected MqttConnecting --> Disconnected: Connect Failed MqttConnected --> RequestingChannel: OpenAudioChannel() RequestingChannel --> ChannelOpened: Hello Exchange Success RequestingChannel --> MqttConnected: Hello Timeout/Failed ChannelOpened --> UdpConnected: UDP Connect Success UdpConnected --> AudioStreaming: Start Audio Transfer AudioStreaming --> UdpConnected: Stop Audio Transfer UdpConnected --> ChannelOpened: UDP Disconnect ChannelOpened --> MqttConnected: CloseAudioChannel() MqttConnected --> Disconnected: MQTT Disconnect
5.2 狀態檢查
裝置透過以下條件判斷音訊通道是否可用:
bool IsAudioChannelOpened() const {
return udp_ != nullptr && !error_occurred_ && !IsTimeout();
}
6. 設定參數
6.1 MQTT 設定
從設定中讀取的設定項目:
endpoint
:MQTT 伺服器地址client_id
:客戶端識別符username
:使用者名稱password
:密碼keepalive
:心跳間隔(預設240秒)publish_topic
:發布主題
6.2 音訊參數
- 格式:Opus
- 取樣率:16000 Hz(裝置端)/ 24000 Hz(伺服器端)
- 聲道數:1(單聲道)
- 幀時長:60ms
7. 錯誤處理與重連
7.1 MQTT 重連機制
- 連線失敗時自動重試
- 支援錯誤上報控制
- 斷線時觸發清理流程
7.2 UDP 連線管理
- 連線失敗時不自動重試
- 依賴 MQTT 通道重新協商
- 支援連線狀態查詢
7.3 逾時處理
基底類別 Protocol
提供逾時檢測:
- 預設逾時時間:120 秒
- 基於最後接收時間計算
- 逾時時自動標記為不可用
8. 安全考量
8.1 傳輸加密
- MQTT:支援 TLS/SSL 加密(埠號8883)
- UDP:使用 AES-CTR 加密音訊資料
8.2 認證機制
- MQTT:使用者名稱/密碼認證
- UDP:透過 MQTT 通道分發金鑰
8.3 防重放攻擊
- 序列號單調遞增
- 拒絕過期資料包
- 時間戳記驗證
9. 效能最佳化
9.1 並行控制
使用互斥鎖保護 UDP 連線:
std::lock_guard<std::mutex> lock(channel_mutex_);
9.2 記憶體管理
- 動態建立/銷毀網路物件
- 智慧指標管理音訊資料包
- 及時釋放加密上下文
9.3 網路最佳化
- UDP 連線重用
- 資料包大小最佳化
- 序列號連續性檢查
10. 與 WebSocket 協議的比較
特性 | MQTT + UDP | WebSocket |
---|---|---|
控制通道 | MQTT | WebSocket |
音訊通道 | UDP (加密) | WebSocket (二進位) |
即時性 | 高 (UDP) | 中等 |
可靠性 | 中等 | 高 |
複雜度 | 高 | 低 |
加密 | AES-CTR | TLS |
防火牆友好度 | 低 | 高 |
11. 部署建議
11.1 網路環境
- 確保 UDP 埠號可達
- 設定防火牆規則
- 考慮 NAT 穿透
11.2 伺服器設定
- MQTT Broker 設定
- UDP 伺服器部署
- 金鑰管理系統
11.3 監控指標
- 連線成功率
- 音訊傳輸延遲
- 資料包遺失率
- 解密失敗率
12. 總結
MQTT + UDP 混合協議透過以下設計實作高效的音視訊通訊:
- 分離式架構:控制與資料通道分離,各司其職
- 加密保護:AES-CTR 確保音訊資料安全傳輸
- 序列化管理:防止重放攻擊和資料亂序
- 自動恢復:支援連線斷開後的自動重連
- 效能最佳化:UDP 傳輸保證音訊資料的即時性
該協議適用於對即時性要求較高的語音互動場景,但需要在網路複雜度和傳輸效能之間做出權衡。
相關文件
- WebSocket 通訊協議 - WebSocket 通訊協議詳細說明
- MCP 協議文件 - MCP 協議互動流程
- MCP 使用指南 - MCP 協議使用方法