MQTT 5.0 報文解析 05:DISCONNECT

歡迎閱讀 MQTT 5.0 報文系列 的第五篇文章。在上一篇中,我們已經介紹了 MQTT 5.0 的 PINGREQ 和 PINGRESP 報文。現在,我們將介紹下一個控制報文:DISCONNECT。

在 MQTT 中,客戶端和服務端可以在斷開網絡連接前向對端發送一個 DISCONNECT 報文,來指示連接關閉的原因。客戶端發送的 DISCONNECT 報文還可以影響服務端在連接斷開後的行爲,例如是否發送遺囑消息,是否更新會話過期間隔。

DISCONNECT 報文示例

我們使用 MQTTX CLI公共 MQTT 服務器 發起一個指定了 Client ID 的客戶端連接,並將 --reconnect-period 設置爲 0 來禁用自動重連,然後在另一個終端中運行相同的命令創建一個使用相同 Client ID 的連接。

整個過程使用 Wireshark 工具來抓取在客戶端與服務器之間往返的 MQTT 報文,Linux 環境可以使用 tcpdump 命令抓取報文,然後導入至 Wireshark 分析。

以下命令將創建一個 Client ID 爲 mqtt-892324 的客戶端連接,爲了避免 Client ID 與別人重複,建議將它改爲其他隨機字符串:

mqttx conn --hostname broker.emqx.io --mqtt-version 5 --client-id mqtt-892324 \ --reconnect-period 0

在我們發起第二個連接後,Wireshark 將捕獲到公共 MQTT 服務器返回給第一個連接的 DISCONNECT 報文:

e0 02 8e 00

這四個十六進制字節,對應着以下報文內容:

DISCONNECT Packet.png

通過下文對 DISCONNECT 報文結構的介紹,你將瞭解到如何從原始的報文數據中提取你想要的信息。

DISCONNECT 報文結構

固定報頭

固定報頭首字節的高 4 位,即報文類型字段的值爲 14(0b1110),低 4 位全部爲 0,表示這是一個 DISCONNECT 報文。

Fixed Header.png

可變報頭

DISCONNECT 報文的可變報頭按順序包含以下字段:

Viriable Header.png

  • 原因碼(Reason Code):一個單字節的無符號整數,用於向對端指示連接斷開的原因。下表列出了在 DISCONNECT 報文中常見的 Reason Code,完整列表可參閱 MQTT 5.0 Reason Code 速查表
Value Reason Code Name Sent By Description
0x00 Normal disconnection 客戶端、服務端 表示連接正常關閉,因此服務端不會發布遺囑消息。
0x04 Disconnect with Will Message 客戶端 連接正常關閉,但客戶端希望服務端仍然發佈遺囑消息。
0x81 Malformed Packet 客戶端、服務端 表示收到了無法按照協議規範正確解析的控制報文,在 MQTT 中我們將這類報文稱爲畸形報文。
0x82 Protocol Error 客戶端、服務端 協議錯誤通常指控制報文在按照協議規範解析以後才能發現的錯誤,包括包含協議不允許的數據、行爲與協議要求不符等等。比如客戶端在一個連接內發送了兩個 CONNECT 報文。
0x8D Keep Alive timeout 服務端 服務端在超過 1.5 倍的 Keep Alive 時間內沒有收到任何報文,因此關閉了連接。
0x8E Session taken over 服務端 另一個更新的使用了且相同的 Client ID 的連接被建立,導致服務端關閉了此連接。
0x93 Receive Maximum exceeded 客戶端、服務端 表示對端同時發送的 QoS > 0 的 PUBLISH 報文數量超過了連接時設置的接收最大值。
0x94 Topic Alias invalid 客戶端、服務端 表示主題別名不合法。比如 PUBLISH 報文中的主題別名值爲 0 或者大於連接時約定的最大主題別名。
0x95 Packet too large 客戶端、服務端 表示報文超過了連接時約定的最大允許長度。
0x98 Administrative action 客戶端、服務端 表示連接因爲管理操作而被關閉,比如運維人員在服務端後臺踢除了客戶端連接。
0x9C Use another server 服務端 表示客戶端應該臨時切換到另一個服務器。如果另一個服務器不是客戶端已知的,那麼還需要配合 Server Reference 屬性一起使用,以告知客戶端新的服務端的地址。
0x9D Server moved 服務端 表示客戶端應該永久切換到另一個服務器。如果另一個服務器不是客戶端已知的,那麼還需要配合 Server Reference 屬性一起使用,以告知客戶端新的服務端的地址。
  • 屬性(Properties):下表列出了 DISCONNECT 報文的所有可用屬性。
Identifier Property Name Sent By Type
0x11 Session Expiry Interval 客戶端 四字節整數
0x1F Reason String 客戶端、服務端 UTF-8 編碼的字符串
0x26 User Property 客戶端、服務端 UTF-8 字符串對
0x1C Server Reference 服務端 UTF-8 編碼的字符串

與之前介紹的其他報文不同,客戶端和服務端在 DISCONNECT 報文中可以使用的原因碼和屬性是不同的,例如 Session Expiry Interval 屬性就只能在客戶端發送的 DISCONNECT 報文中使用,所以我們在上面的列表中均列出了它們的可用範圍。

有效載荷

DISCONNECT 報文不包含有效載荷。

總結

客戶端和服務端都可以發送 DISCONNECT 報文,表示準備斷開網絡連接,報文中的原因碼可以向接收方指示連接關閉的原因。當 MQTT 連接意外斷開時,我們可以優先查看是否收到了 DISCONNECT 報文以及報文中原因碼的值。

雖然客戶端和服務端在 DISCONNECT 報文中可以用的原因碼和屬性存在差異,但我們並不需要強行去記憶它們。它們通常都和對應的機制與行爲相關,例如遺囑消息只會由服務端發佈,所以希望連接正常關閉但對端仍要發佈遺囑消息的原因碼 0x04,也會被客戶端使用。

以上就是對 DISCONNECT 報文的介紹,在下一篇文章中我們將介紹 MQTT 5.0 增強認證特性所使用的 AUTH 報文,它也是 MQTT 中最後一個報文類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章