背景
keep alive 是 CONNECT 報文中可變頭的一部分。
我們提到過 Broker 需要知道 Client 是否非正常地斷開了和它的連接,以發送遺願消息。實際上 Client 也需要能夠很快地檢測到它失去了和 Broker 的連接,以便重新連接。
MQTT 協議是基於 TCP 的一個應用層協議,理論上 TCP 協議在丟失連接時會通知上層應用,但是 TCP 有一個半打開連接的問題(half-open connection)。這里我不打算深入分析 TCP 協議,需要記住的是,在這種狀態下,一端的 TCP 連接已經失效,但是另外一端並不知情,它認為連接依然是打開的,它需要很長的時間才能感知到對端連接已經斷開了,這種情況在使用移動或者衛星網絡的時候尤為常見。
所以,僅僅依賴 TCP 層的連接狀態監測是不夠的,於是 MQTT 協議設計了一套 Keep Alive 機制。回憶一下,在建立連接的時候,我們可以傳遞一個 Keep Alive 參數,它的單位為秒,MQTT 協議中約定:在 1.5*Keep Alive 的時間間隔內,如果 Broker 沒有收到來自 Client 的任何數據包,那么 Broker 認為它和 Client 之間的連接已經斷開;同樣地, 如果 Client 沒有收到來自 Broker 的任何數據包,那么 Client 認為它和 Broker 之間的連接已經斷開。
MQTT 還有一對 PINGREQ/PINGRESP 數據包,當 Broker 和 Client 之間沒有任何數據包傳輸的時候,可以通過 PINGREQ/PINGRESP 來滿足 Keep Alive 的約定和偵測連接狀態。
對於 Keep Alive 機制,我們還需要記住以下幾點:
- 如果在一個 Keep Alive 時間間隔內,Client 和 Broker 有過數據包傳輸,比如 PUBLISH,Client 就沒有必要再使用 PINGREQ 了,在網絡資源比較緊張的情況下這點很重要;
- Keep Alive 值是由 Client 指定的,不同的 Client 可以指定不同的值;
- Keep Alive 的最大值為 18 小時 12 分 15 秒;
- Keep Alive 值如果設為 0 的話,代表不使用 Keep Alive 機制。
說明
如果沒有任何其它的控制報文可以發送,客戶端必須發送一個PINGREQ報文。
不管保持連接的值是多少,客戶端任何時候都可以發送PINGREQ報文,並且使用PINGRESP報文判斷網絡和服務端的活動狀態。
如果保持連接的值非零,並且服務端在一點五倍的保持連接時間內沒有收到客戶端的控制報文,它必須斷開客戶端的網絡連接,認為網絡連接已斷開。
客戶端發送了PINGREQ報文之后,如果在合理的時間內仍沒有收到PINGRESP報文,它應該關閉到服務端的網絡連接。
PINGREQ – 心跳請求 報文
當 Client 在一個 Keep Alive 時間間隔內沒有向 Broker 發送任何數據包,比如 PUBLISH 和 SUBSCRIBE 的時候,它應該向 Broker 發送 PINGREQ
數據包。
PINGREQ 數據包沒有可變頭(Variable header)和消息體(Payload),那么,PINGREQ 報文的全部內容(共2個字節)就是 : 0xc0 0x00
PINGRESP – 心跳響應 報文
當 Broker 收到來自 Client 的 PINGREQ 數據包,它應該回復 Client 一個 PINGRESP 數據包。
PINGRESP 數據包沒有可變頭(Variable header)和消息體(Payload),那么,PINGRESP 報文的全部內容(共2個字節)就是 : 0xd0 0x00