「在百元級門禁機上做網路通訊,最天真的想法就是以為網路永遠很順;真正的工業級架構,是把每一天都當作『隨時會斷網、隨時會被拔插頭』的世界末日來設計。」

前面幾篇我們把高通驍龍 QM215(4 顆 A53、2GB RAM)的系統瘦身與相機零複製榨到了極致。
但當門禁機掛上工廠大門時,現場的網路比晶片更殘酷:裝置躲在企業內網深處(192.168.1.X 無公網 IP)、網路線隨時被拔、DNS 動輒卡死 30 秒、雲端後台隨時可能掛掉重啟。
在邊緣 IoT 系統中,WebSocket 與 RESTful API 到底該如何精準分工,做到「0.1 秒即時開門、零記憶體負擔、斷網 3 天也能穩健重連」?
一、 為什麼必須用 WebSocket?
在邊緣裝置中,傳統 HTTP 短輪詢(Polling)在工廠現場會立刻遇到兩大死穴:
1. 延遲與伺服器當機的死循環
- 5 秒輪詢一次:訪客站在門口按鈴,平均要乾等 2.5 秒門才會開,體驗極差。
- 200ms 輪詢一次:全廠 100 台裝置每秒產生 500 次請求,高達 4 個 RTT 的 TCP/TLS 交握瞬間打爆地端的小伺服器。
2. 內網 NAT 穿透困境
門禁機沒有公網 IP,雲端伺服器完全無法主動發起 HTTP POST 發送開門指令。裝置必須在開機時主動向雲端伺服器建立 WebSocket 長連線,在防火牆上鑿出永久雙向通道(Pinhole):
- 下行即時控制:0.1 秒遠端開門、即時撤銷離職員工特徵、訪客動態密碼驗證。
- 上行即時回報:刷臉打卡抓拍照即時上傳、防拆機警報。
- 通道保活:15 秒輕量心跳維持防火牆通道暢通。
二、 為什麼大檔案不能進 WebSocket?RESTful API 的不可替代性
如果把所有功能全部塞進 WebSocket,現場會立刻引發嚴重的開門卡死事故。RESTful API 有其專屬戰場:
1. 第三方系統(HR 考勤 / ERP)標準無縫對接
由後台伺服器提供標準 RESTful API,客戶用最熟悉的 HTTP 即可串接,無需在他們的系統維護脆弱的長連線。
2. 50MB 韌體升級與大檔案下載
50MB APK 更新檔、3D 鏡頭韌體與高解析度照片批次下載,必須走標準 HTTP 進行分段流式傳輸與斷點續傳。
3. 防禦 TCP 隊首阻塞(高速公路塞車效應)
WebSocket 底層為單一 TCP 連線。若將 50MB 韌體塞進 WebSocket,會瞬間佔滿整條連線;此時若突發「緊急開門」指令,開門封包被迫排在 50MB 檔案後面等幾十秒(Head-of-Line Blocking),導致大門卡死打不開!
將「大檔案傳輸(HTTP REST)」與「即時信令(WebSocket)」物理隔離,是保證 0.1 秒秒開門的關鍵底線。
三、 資料傳輸大瘦身:為何選「Protobuf over WebSocket」?
1. Base64 讓記憶體直接爆炸
早期將現場照片轉為 Base64 字串塞進 JSON 傳輸:
- 體積膨脹 33%,浪費網路頻寬。
- 一張 150KB JPEG 轉成 Base64 會在 Java 記憶體產生 200KB 的 String 垃圾。尖峰期頻繁觸發 GC,相機預覽直接從 30fps 掉到個位數導致人臉丟幀。
2. 最佳解答:Protobuf over WebSocket 全端大一統
維持單一 WebSocket 埠號,Payload 全面換成 Google Protocol Buffers:
syntax = "proto3";
package com.edge.ai.gate;
message PassEventPacket {
string device_id = 1;
int64 timestamp = 2;
string user_id = 3;
bool is_authorized = 4;
// 原生二進位 byte 陣列直入,0 Base64、0 額外字串記憶體垃圾!
bytes rgb_image = 5;
bytes ir_image = 6;
bytes depth_image = 7;
}
- 門禁機端:JPEG 位元組直接塞進 Protobuf,Java 記憶體垃圾歸零,封包比 JSON 小 60%。
- 警衛室 Web 端:Chrome 瀏覽器原生
new WebSocket()直連,掛載protobuf.js一行程式碼解碼,零額外代理依賴!
四、 邊緣裝置的穩定性實戰:單執行緒事件排隊
網路連線(DNS 解析、TCP 交握、心跳)交由專屬 HandlerThread 在背景單行道依序排隊:
- UI 零延遲:UI 呼叫僅丟 Message 排隊,0.01ms 立刻返回。
- 內部狀態封閉:Socket 實體完全封裝在背景執行緒中,免除複雜跨執行緒加鎖。
public class WebSocketWorkerManager {
private HandlerThread mWorkerThread;
private Handler mWorkerHandler;
public void init() {
mWorkerThread = new HandlerThread("ws-worker-thread");
mWorkerThread.start();
mWorkerHandler = new Handler(mWorkerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
// 所有網路連線、斷線重試與資料發送全在單一執行緒依序執行
}
};
}
}
五、 工業級離線自救:斷網 3 天也能穩健重連
工廠現場隨時可能斷網 3 天。我們建立了三層防禦:
- 退避演算法防打爆伺服器:連線失敗時,重連間隔以指數退避(Exponential Backoff):
2s -> 4s -> 8s -> 16s -> 最大 60s,並加入隨機抖動(Jitter),防止全廠 100 台門禁機在網路恢復瞬間形成「雪崩效應」把雲端伺服器打爆。 - 本地 SQLite 離線打卡佇列:斷網期間所有通行紀錄與拍照存入本地 SQLite。連線恢復後以「批次 20 筆」非同步回傳,絕不佔用相機推論記憶體。
- 白名單離線認證:特徵庫 100% 本地儲存。即便網路徹底斷絕,門禁機依然能以 3ms 速度秒級刷臉開門。
工控 IoT 通訊鐵則與收工
- 信令與大檔必須物理分流:WebSocket 只傳信令與輕量事件,大檔案堅決走 HTTP。
- 二進位協定是記憶體救星:拒絕 JSON 與 Base64,Protobuf 是弱晶片維持 0-GC 的唯一生路。
- 把斷網當常態:離線儲存、指數退避、本地認證,門禁機才能在荒野中長生不老。
下一篇,我們聊聊那個讓人又愛又恨的功能:WebRTC 即時視訊對講,如何在雙鏡頭相機被 AI 霸佔的情況下實現無縫切換!
感謝觀看,收工。

發佈留言