MQTTv5.0協議詳解

一、MQTT協議具體是什麼

MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協議),基於TCP/IP的長連接。MQTT是機器對機器(M2M)/物聯網(IoT)連接協議,發佈/訂閱模式,是專爲受限設備和低帶寬、高延遲、不可靠網絡而設計。作爲一種低開銷、低時延、低帶寬佔用的即時通訊協議,MQTT在物聯網、小型設備、移動應用等方面有廣泛的應用。

目前最新版本爲:v5.0,在v3.1.1版本的基礎上增加了會話/消息延時功能、原因碼、主題別名、in-flight流控、屬性、共享訂閱等功能,增加了用於增強認證的AUTH報文。

二、MQTT協議數據格式

每條MQTT消息最多由三部分組成,始終排列爲(固定的報頭 | 可變包頭 | 有效負荷),如下所示:

固定報頭(Fixed Header),存在於所有MQTT控制數據包中
可變報頭(Variable Header),存在於某些MQTT控制數據包中

有效負載(Payload),存在於某些MQTT控制數據包中

1、固定報頭(Fixed Header),以Connect連接爲例說明

MQTT固定報頭最少2個字節,第一個字節包含MQTT控制報文類型控制報文類型的【標誌位】;第二個字節開始是剩餘長度字段,該長度是後面的【可變報頭】和【有效負載】的總長度,該字段最多允許4個字節。

位(Bit) 7 6 5 4 3 2 1 0
第一字節(byte) MQTT控制報文類型 控制報文類型的標誌位(目前只在Publish協議中使用)
0 0 0 1 0 0 0 0
第二字節(byte 2)...... 剩餘長度:可變報頭和有效負載的總長度(最長可達4字

1.1 MQTT控制報文類型(第1字節的7~4,4位無符號值):

名稱 描述
Reserved 0(0000) 預留
Connect 1(0001) 客戶端請求連接服務端
ConnectAck 2(0010) 服務端確認連接建立
Publish 3(0011) 發佈消息請求
PublishAck 4(0100) 發佈消息確認
PubRec 5(0101) 發佈消息收到
PubRel 6(0110) 發佈消息釋放
PubComp 7(0111) 發佈消息完成
Subscribe 8(1000) 訂閱消息請求
SubAck 9(1001) 訂閱消息確認
UnSubscribe 10(1010) 取消訂閱請求
UnSubAck 11(1011) 取消訂閱確認
PingReq 12(1100) 客戶端發送Ping命令(心跳包)
PingResp 13(1101) Ping命令應答
Disconnect 14(1110) 斷開連接

Reserved

Auth

15(1111)

保留(v3.1.1)

認證交換(v5.0)

1.2 標誌位(第1字節,二進制位3~0,4位無符號值):

MQTT控制包 標誌位 3位 2位 1位 0位
Connect 預留 0 0 0 0
ConnAck 預留 0 0 0 0
Publish MQTT v3.1.1和v5.0中使用 DUP Qos Qos Retain
PubAck 預留 0 0 0 0
PubRec 預留 0 0 0 0
PubRel 預留 0 0 1 0
PubComp 預留 0 0 0 0
Subscribe 預留 0 0 1 0
SubAck 預留 0 0 0 0
UnSubscribe 預留 0 0 1 0
UnSubAck 預留 0 0 0 0
PingReq 預留 0 0 0 0
PingResp 預留 0 0 0 0
Disconnect 預留 0 0 0 0
Auth 預留 0 0 0 0

注:此處的報文不能轉化爲十進制計算

例:0100表示,0:當前消息第一次發送,10消息質量爲2,Retain標誌位0

DUP:重複發送Publish數據包次數

Qos:消息質量

Retain:Publish消息保留標誌

注:由上表可以看出標誌位目前只在Publish協議中使用

 1.3 剩餘長度:

如何確定其長度到底是1還是4呢,這取決於字節的最高位Bit 7(默認都是高字節在前),MQTT協議規定,如果這個值是1,那麼就繼續計算字節長度,如果是0,那麼就不再計算字節長度。即Bit7起“延續位”作用。

由於MQTT協議最多隻允許使用四個字節表示剩餘長度,並且最後一字節最大值只能是0x7F不能是0xFF,所以能發送的最大消息長度是128*128*128*128Byte / 1024 / 1024 = 256MB,而不是512MB。

舉例如下:

消息假設長度是[0X60],其二進制是01100000,字節最高位Bit7(從左邊起第0位)是0,所以不需要繼續往後計算。那麼消息長度就是0X60,十進制數是96。

如果消息長度是[0XC1, 0XC2, 0X33],那麼他們的二進制分別如下,

0xC1=1100 0001

0xC2=1100 0010

0x33=0011 0011,

第一字節最高位是1,那麼需要繼續向後計算,去掉標記位(0xC1%128),得到100 0001=41

第二字節最高位是1,那麼需要繼續向後計算,去掉標記位(0xC2%128),得到100 0010=42

第三字節最高位是0,不需要向後計算,其結果就是0x33=51

因爲低位在前,高位在後,那麼長度計算爲Length=41 + 42*128 + 51*128*128=841001 B = 821KB

需要注意的是,消息長度=可變頭部長度+消息內容長度。不包括首字節和消息長度本身,如果消息長度爲5,那麼說明這條消息後邊還有5字節,整條消息長度爲7(首字節+1位長度字節+5)。

另外如果消息長度爲4字節,最後一位不能超過0X7F=127,因爲如果超出這個值,其最高位Bit7是1,還需要往後計算,這與消息最大長度爲4字節矛盾。所以如果出現[0XFF, 0XFF, 0XFF, 0XFF]這樣的消息長度,那麼接收方認爲這是一條非法的消息。

2、可變報頭(Variable Header),以Connect連接爲例說明

某些類型的MQTT控制包包含可變報頭組件。它位於固定標題和有效負載之間。可變報頭的內容取決於數據包類型。可變報頭的數據包標識符字段在幾種數據包類型中很常見。可變報頭主要包含協議名、協議版本、連接標誌(Connect Flags)、心跳間隔時間(Keep Alive )。

2.1、協議名稱,在可變報頭中佔用前6字節

 

描述

7

6

5

4

3

2

1

0

協議名稱

字節1

長度MSB(0)

0

0

0

0

0

0

0

0

字節2

長度LSB(4)

0

0

0

0

0

1

0

0

字節3

'M'

0

1

0

0

1

1

0

1

字節4

'Q'

0

1

0

1

0

0

0

1

字節5

'T'

0

1

0

1

0

1

0

0

字節6

'T'

0

1

0

1

0

1

0

0

協議名稱是UTF-8編碼的字符串,代表協議名稱“ MQTT”,大寫。

2.2、協議版本,在可變報頭中佔用第7個字節

 


描述

7

6

5

4

3

2

1

0

協議等級

字節7

版本(5)

0

0

0

0

0

1

0

1

一個字節的無符號值,表示客戶端使用的協議的修訂級別。

協議版本5.0的“協議版本”字段的值爲5(0x05)。

協議版本3.1.1的“協議級別”字段的值爲4(0x04)

2.3、連接標誌,在可變報頭中佔用第8個字節

7

6

5

4

3

2

1

0

 

用戶名標誌

密碼標誌

Will Retain

Will  QoS

Will  Flag

Clean Session(v3.1.1)

Clean Start(v5.0)

已預留

字節8

X

X

X

X

X

X

X

0

2.3.1、Clean Start(連接標誌的位1)

如果在Clean Start設置爲1的情況下收到CONNECT數據包,則客戶端和服務器務必丟棄任何現有的會話並開始新的會話

如果接收到的CONNECT數據包的Clean Start設置爲0,並且有一個與客戶端標識符相關聯的會話,則服務器務必根據現有會話 狀態恢復與客戶端的通信。如果接收到的CONNECT數據包的Clean Start設置爲0,並且沒有與客戶端標識符關聯的會話,則服務器必須創建一個新的會話 。

 2.3.2、Will  Flag(連接標誌的位2)

如果爲1表示開啓遺囑通知,

發佈遺囑消息的情況包括但不限於:

  • 服務器檢測到I / O錯誤或網絡故障。
  • 客戶端在保持活動時間內無法通信。
  • 客戶端關閉網絡連接,而無需先發送原因碼爲0x00(正常斷開連接)的DISCONNECT數據包。
  • 服務器在沒有首先收到原因碼爲0x00(正常斷開連接)的DISCONNECT數據包的情況下關閉了網絡連接。

2.3.3、Will Qos(連接標誌的位3和位4)

這兩位指定發佈遺囑消息時要使用的QoS級別。

如果將Will Flag設置爲0,則Will QoS必須設置爲0 (0x00)。

如果將Will Flag設置爲1,則Will QoS的值可以爲0(0x00),1(0x01)或2(0x02)。 值3(0x03)是格式錯誤的數據包。

2.3.4 Will Retain 消息保留(連接標誌的位5)

該位指定在發佈遺囑消息時是否保留該遺囑消息。

如果遺囑標誌設置爲0,則遺囑保留必須設置爲0。如果將Will Flag設置爲1並將Will Retain設置爲0,則服務器必須將Will消息發佈爲非保留消息。如果將Will Flag設置爲1並將Will Retain設置爲1,則服務器必鬚髮布Will消息作爲保留消息。

2.3.5 Password Flag 密碼標誌 (連接標誌的位6)

如果密碼標誌設置爲0,則有效負載 中絕對不能存在密碼。 如果密碼標誌設置爲1,則有效負載中必須存在密碼。

該協議的該版本允許發送不帶用戶名的密碼,而MQTT v3.1.1則不允許。這反映出密碼通常用於密碼而不是密碼。

2.3.6 UserName Flag 用戶名標誌 (連接標誌的位7)

如果用戶名標誌設置爲0,則有效載荷中不得存在用戶名。 如果用戶名標誌設置爲1,則用戶名必須出現在有效負載。

2.4、 Keep Alive 保活機制,在可變報頭中佔用第9和10字節

7

6

5

4

3

2

1

0

字節9

Keep Alive MSB

字節10

Keep Alive LSB

Keep Alive是兩個字節的整數,它是一個以秒爲單位的時間間隔。它是客戶端完成傳輸一個MQTT控制數據包的時間點與它開始發送下一個MQTT控制數據點的時間之間允許的最大時間間隔。客戶有責任確保發送的MQTT控制包之間的間隔不超過Keep Alive值。如果Keep Alive不爲零且在沒有發送任何其他MQTT控制包的情況下,客戶端必鬚髮送PINGREQ包,相應的,服務器會返回一個PINGRESP消息進行確認。如果服務器在一個半(1.5)心跳間隔時間週期內沒有收到來自客戶端的消息,就會斷開與客戶端的連接。心跳間隔時間最大值大約可以設置爲18個小時,0值意味着客戶端不斷開。

3、有效負載(Payload)

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