MQTT 5.0 報文解析 01:CONNECT 與 CONNACK

MQTT 5.0 報文介紹 中,我們介紹了 MQTT 報文由固定報頭、可變報頭和有效載荷三個部分組成,以及可變字節整數、屬性這類 MQTT 報文中的通用概念。現在,我們將按照實際的用途來進一步介紹各個類型的報文的組成。首先,我們將專注於用於建立 MQTT 連接的報文。

如果我們想要使用 MQTT 進行通信,第一步必然是建立一個 MQTT 連接,而建立 MQTT 連接需要用到兩個控制報文,它們分別是 CONNECT 報文與 CONNACK 報文。CONNECT 報文是客戶端與服務端建立網絡連接後,向服務端發送的第一個控制報文,用來發起連接請求。服務端將返回 CONNACK 報文告知客戶端連接結果。

報文示例

我們使用 MQTTX CLI公共 MQTT 服務器 發起一個連接,在這個連接中,我們將協議版本設置 MQTT 5.0,Clean Start 設置爲 1,Session Expiry Interval 設置爲 300 秒,Keep Alive 設置爲 60,用戶名和密碼分別設置爲 admin 和 public,對應的 MQTTX CLI 命令爲:

mqttx conn --hostname broker.emqx.io --mqtt-version 5 \  --session-expiry-interval 300 --keepalive 60 --username admin --password public

以下是使用 Wireshark 工具抓取到的 MQTTX CLI 發出的 CONNECT 報文,Linux 環境可以先使用 tcpdump 命令抓取報文,然後再導入至 Wireshark 查看:

10 2f 00 04 4d 51 54 54 05 c2 00 3c 05 11 00 00 01 2c 00 0e 6d 71 74 74 78 5f 30 63 36 36 38 64 30 64 00 05 61 64 6d 69 6e 00 06 70 75 62 6c 69 63

但這是一串不易理解的十六進制字節,除非它們被轉換成以下格式:

01connectpacket.png

同樣我們也抓取到了公共 MQTT 服務器返回的 CONNACK 報文:

20 13 00 00 10 27 00 10 00 00 25 01 2a 01 29 01 22 ff ff 28 01

在解析這串報文數據之後我們可以看到,CONNACK 報文的 Reason Code 爲 0,表示連接成功,後面的多個屬性則給出了服務器支持的功能列表,比如支持的最大報文長度,是否支持保留消息等等:

02connackpacket.png

當然,Wireshark 其實也已經爲我們列出了報文中各個字段的值,通過下文對 CONNECT 和 CONNACK 報文結構的介紹,再結合 Wireshark 的抓包結果按圖索驥,你將很快掌握這兩個報文:

03wireshark.png

CONNECT 報文結構

固定報頭

CONNECT 報文的固定報頭中,位於首字節高 4 位的報文類型字段的值必須爲 1(0b0001),首字節中低 4 位則固定全爲 0。

所以,CONNECT 報文的第一個字節的值必然爲 0x10,我們可以以此來判斷某個報文是否爲 CONNECT 報文。

MQTT CONNECT 固定報頭

可變報頭

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

MQTT CONNECT 可變報頭

  • Protocol Name:這是一個 UTF-8 編碼的字符串,用來表示協議名稱。在 MQTT 中,UTF-8 編碼的字符串的前兩個字節統一用於指示後面實際的字符數據的長度。MQTT 3.1.1 和 MQTT 5.0 中協議名稱固定爲 MQTT,所以對應的以十六進制字節表示的完整內容就是 00 04 4d 51 54 54,其中 4d 51 54 54 就是 MQTT 這個字符串對應的 ASCII 值。最早的 MQTT 3.1 中的協議名稱是 MQIsdp,所以它對應的是 00 06 4d 51 49 73 64 70

  • Protocol Version:這是一個單個字節長度的無符號整數,用來表示協議版本。目前只有三個可取值,3 表示 MQTT 3.1,4 表示 MQTT 3.1.1,5 表示 MQTT 5.0。

  • Connect Flags:連接標識,它只有一個字節,但包含了多個用於控制連接行爲或指示有效載荷中某些字段是否存在的參數。

    MQTT Connect Flags

    • User Name Flag:用於指示有效載荷是否包含用戶名字段。

    • Password Flag:用於指示有效載荷是否包含密碼字段。

    • Will Retain:用於指示遺囑消息是否爲保留消息。

    • Will QoS:用於指示遺囑消息的 QoS。

    • Will Flag:用於指示有效載荷是否包含了遺囑消息的相關字段。

    • Clean Start:用於指示當前連接是一個新的會話還是一個已存在會話的延續,這決定了服務端將直接新建會話還是嘗試複用已存在的會話。

    • Reserved:這是一個保留位,它的值必須爲 0。

  • Keep Alive:這是一個雙字節長度的無符號整數,用來表示客戶端發送兩個相鄰的控制報文的最大時間間隔。

  • Properties:下表列出了 CONNECT 報文的所有可用屬性。

Identifier Property Name Type
0x11 Session Expiry Interval 四字節整數
0x21 Receive Maximum 雙字節整數
0x27 Maximum Packet Size 四字節整數
0x22 Topic Alias Maximum 雙字節整數
0x19 Request Response Information 單字節
0x17 Request Problem Information 單字節
0x26 User Property UTF-8 字符串對
0x15 Authentication Method UTF-8 編碼的字符串
0x16 Authentication Data 二進制數據

有效載荷

CONNECT 報文有效載荷中的字段,除了 Client ID 以外,其他字段都是可選的,它們是否存在取決於可變報頭的 Connect Flags 中對應標誌位的值。但如果這些存在,就必須按照 Client ID、Will Properties、Will Topic、Will Payload、User Name、Password 的順序出現。

MQTT 有效載荷

CONNACK 報文結構

固定報文

固定報頭中首字節的高 4 位值爲 2(0b0010),表示這是一個 CONNACK 報文。

MQTT CONNACK 固定報文

可變報頭

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

MQTT CONNACK 可變報頭

  • Connect Acknowledge Flags:連接確認標誌。

    • Reserved (Bit 7 - 1):保留位,必須設置爲 0.

    • Session Present (Bit 0):用於指示服務端是否正在使用已存在的會話與客戶端恢復通信。僅在客戶端在 CONNECT 連接中將 Clean Start 設置爲 0 時,Session Present 可能爲 1。

  • Reason Code:用於指示連接結果。下表列出了一些在 CONNACK 報文中常見的 Reason Code,完整列表可參閱 MQTT 5.0 Reason Code 速查表

Value Reason Code Name Description
0x00 Success 連接被接受。
0x81 Malformed Packet 服務端無法按照協議規範正確解析 CONNECT 報文,例如保留位沒有按照協議要求設置爲 0。
0x82 Protocol Error CONNECT 報文可以被正確解析,但是內容不符合協議規範,比如 Will Topic 字段的值不是一個合法的 MQTT 主題。
0x84 Unsupported Protocol Version 服務端不支持客戶端所請求的 MQTT 協議版本。
0x85 Client Identifier not valid 表示 Client ID 是有效的字符串,但是不被服務端接受,比如 Client ID 超出了服務端允許的最大長度。
0x86 Bad User Name or Password 客戶端因爲使用了錯誤的用戶名或密碼而被拒絕連接。
0x95 Packet too large CONNECT 報文超過了服務端允許的最大長度,可能是因爲攜帶了較大的遺囑消息。
0x8A Banned 表示客戶端被禁止登錄。例如服務端檢測到客戶端的異常連接行爲,所以將這個客戶端的 Client ID 或者 IP 地址加入到了黑名單列表中,又或者是後臺管理人員手動封禁了這個客戶端,當然以上這些通常需要視服務端的具體實現而定。
  • Properties:下表列出了 CONNACK 報文的所有可用屬性。
Identifier Property Name Type
0x11 Session Expiry Interval 四字節整數
0x21 Receive Maximum 雙字節整數
0x24 Maximum QoS 單字節
0x25 Retain Available 單字節
0x27 Maximum Packet Size 四字節整數
0x12 Assigned Client Identifier UTF-8 編碼的字符串
0x22 Topic Alias Maximum 雙字節整數
0x1F Reason String UTF-8 編碼的字符串
0x26 User Property UTF-8 字符串對
0x28 Wildcard Subscription Available 單字節
0x29 Subscription Identifier Available 單字節
0x2A Shared Subscription Available 單字節
0x13 Server Keep Alive 雙字節整數
0x1A Response Information UTF-8 編碼的字符串
0x1C Server Reference UTF-8 編碼的字符串
0x15 Authentication Method UTF-8 編碼的字符串
0x16 Authentication Data 二進制數據

有效載荷

CONNACK 報文不包含有效載荷。

總結

CONNECT 是客戶端與服務端的網絡連接建立後,客戶端發送的第一個 MQTT 報文,CONNACK 作爲 CONNECT 的響應報文通過原因碼來指示連接結果。

客戶端和服務端需要藉助 CONNECT 和 CONNACK 報文來完成必要信息的交換,例如客戶端使用的協議版本、Client ID、用戶名、密碼,以及服務端是否存在相應的會話、支持的最大報文長度和最大 QoS 等級等等。

以上就是對 MQTT CONNECT 和 CONNACK 報文的介紹,在後續的文章中,我們還會繼續研究 PUBLISH、DISCONNECT 這些報文的結構和組成。

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