4、MQTT報文格式


1、MQTT 控制報文格式

  MQTT 控制報文的結構

  在MQTT協議中,一個MQTT數據包由:固定頭(Fixed header)、可變頭(Variable header)、消息體(payload)三部分構成。MQTT數據包結構如下:

  (1)固定頭(Fixed header):存在於所有MQTT數據包中,表示數據包類型及數據包的分組類標識。
  (2)可變頭(Variable header):存在於部分MQTT數據包中,數據包類型決定了可變頭是否存在及其具體內容。
  (3)消息體(Payload):存在於部分MQTT數據包中,表示客戶端收到的具體內容。

  1.1、 固定報頭

  每個 MQTT 控制報文都包含一個固定報頭。固定報頭的格式如下圖所示:

  MQTT固定報文頭最少有兩個字節,第一字節包含消息類型(Message Type)和QoS級別等標志位。第二字節開始是剩余長度字段,該長度是后面的可變報文頭加消息負載的總長度,該字段最多允許四個字節。

  剩余長度字段單個字節最大值為二進制0b0111 1111,16進制0x7F。也就是說,單個字節可以描述的最大長度是127字節。為什么不是256字節呢?因為MQTT協議規定,單個字節第八位(最高位)若為1,則表示后續還有字節存在,第八位起“延續位”的作用。

  例如,數字64,編碼為一個字節,十進制表示為64,十六進制表示為0×40。數字321(65+2*128)編碼為兩個字節,重要性最低的放在前面,第一個字節為65+128=193(0xC1),第二個字節是2(0x02),表示2×128。

  由於MQTT協議最多只允許使用四個字節表示剩余長度(如表1),並且最后一字節最大值只能是0x7F不能是0xFF,所以能發送的最大消息長度是256MB,而不是512MB。

  (1)MQTT 控制報文的類型

  位置:byte1, bit7-bit4。

  表示為 4 位無符號值, 這些值的定義見下表---控制報文的類型 

名字

報文流動方向

描述

Reserved

0

禁止

保留

CONNECT

1

客戶端到服務端

客戶端請求連接服務端

CONNACK

2

服務端到客戶端

連接報文確認

PUBLISH

3

兩個方向都允許

發布消息

PUBACK

4

兩個方向都允許

QoS 1 消息發布收到確認

PUBREC

5

兩個方向都允許

發布收到(保證交付第一步)

PUBREL

6

兩個方向都允許

發布釋放(保證交付第二步)MQTT-3.1.1-CN 15

PUBCOMP

7

兩個方向都允許

QoS 2 消息發布完成(保證交互第三步)

SUBSCRIBE

8

客戶端到服務端

客戶端訂閱請求

SUBACK

9

服務端到客戶端

訂閱請求報文確認

UNSUBSCRIBE

10

客戶端到服務端

客戶端取消訂閱請求

UNSUBACK

11

服務端到客戶端

取消訂閱報文確認

PINGREQ

12

客戶端到服務端

心跳請求

PINGRESP

13

服務端到客戶端

心跳響應

DISCONNECT

14

客戶端到服務端

客戶端斷開連接

Reserved

15

禁止

保留

  固定報文頭中的第一個字節包含連接標志(Connect Flags),連接標志用來區分MQTT的消息類型。MQTT協議擁有14種不同的消息類型,可簡單分為連接及終止、發布和訂閱、QoS 2消息的機制以及各種確認ACK。

  (2)、用於指定控制報文類型的標志位

  固定報頭第 1 個字節的剩余的 4 位 [3-0]包含每個 MQTT 控制報文類型特定的標志。

  表格中任何標記為“保留”的標志位, 都是保留給以后使用的, 必須設置為表格中列出的值 。 在不使用標識位的消息類型中,標識位被作為保留位。如果收到無效的標志時,接收端必須關閉網絡連接。

控制報文

固定報頭標志

Bit 3

Bit 2

Bit 1

Bit 0

CONNECT

Reserved

0

0

0

0

CONNACK

Reserved

0

0

0

0

PUBLISH

Used in MQTT 3.1.1

DUP1

QoS2

QoS2

RETAIN3

PUBACK

Reserved

0

0

0

0

PUBREC

Reserved

0

0

0

0

PUBREL

Reserved

0

0

1

0

PUBCOMP

Reserved

0

0

0

0

SUBSCRIBE

Reserved

0

0

1

0

SUBACK

Reserved

0

0

0

0

UNSUBSCRIBE

Reserved

0

0

1

0

UNSUBACK

Reserved

0

0

0

0

PINGREQ

Reserved

0

0

0

0

PINGRESP

Reserved

0

0

0

0

DISCONNECT

Reserved

0

0

0

0

 

  DUP:發布消息的副本。用來在保證消息的可靠傳輸,如果設置為1,則在下面的變長中增加MessageId,並且需要回復確認,以保證消息傳輸完成,但不能用於檢測消息重復發送。

  QoS:發布消息的服務質量,即:保證消息傳遞的次數
    00:最多一次(QoS==0),即:<=1。消息發布完全依賴底層 TCP/IP 網絡。協議里沒有定義應答和重試,會發生消息丟失或重復。消息要么只會到達服務端一次,要么根本沒有到達。這一級別可用於如下情況,環境傳感器數據,丟失一次讀記錄無所謂,因為不久后還會有第二次發送。
    01:至少一次(QoS==1),即:>=1。確保消息到達,但消息重復可能會發生。服務器的消息接收由PUBACK消息進行確認,如果通信鏈路或發送設備異常,或者指定時間內沒有收到確認消息,發送端會重發這條在消息頭中設置了DUP位的消息。
    10:只有一次(QoS==2),即:=1。確保消息到達一次。這是最高級別的消息傳遞,消息丟失和重復都是不可接受的,使用這個服務質量等級會有額外的開銷。 這一級別可用於如下情況,在計費系統中,消息重復或丟失會導致不正確的結果。小型傳輸,開銷很小(固定長度的頭部是 2 字節),協議交換最小化,以降低網絡流量。
    11:預留

    比如目前流行的共享單車智能鎖,智能鎖可以定時使用QoS level 0質量消息請求服務器,發送單車的當前位置,如果服務器沒收到也沒關系,反正過一段時間又會再發送一次。之后用戶可以通過App查詢周圍單車位置,找到單車后需要進行解鎖,這時候可以使用QoS level 1質量消息,手機App不斷的發送解鎖消息給單車鎖,確保有一次消息能達到以解鎖單車。最后用戶用完單車后,需要提交付款表單,可以使用QoS level 2質量消息,這樣確保只傳遞一次數據,否則用戶就會多付錢了。

  RETAIN: 發布保留標識,表示服務器要保留這次推送的信息,如果有新的訂閱者出現,就把這消息推送給它,如果設有那么推送至當前訂閱者后釋放。

  (3)、 剩余長度

  位置: 從第 2 個字節開始。

  固定頭的第二字節用來保存變長頭部和消息體的總大小的,但不是直接保存的。這一字節是可以擴展,其保存機制,前7位用於保存長度,后一部用做標識。當最后一位為1時,表示長度不足,需要使用二個字節繼續保存。例如:計算出后面的大小為0

  剩余長度(Remaining Length) 表示當前報文剩余部分的字節數, 包括可變報頭和負載的數據。 剩余長度不包括用於編碼剩余長度字段本身的字節數。

  剩余長度字段使用一個變長度編碼方案, 對小於 128 的值它使用單字節編碼。 更大的值按下面的方式處理。低 7 位有效位用於編碼數據,最高有效位用於指示是否有更多的字節。 因此每個字節可以編碼 128 個數值和一個延續位(continuation bit) 。 剩余長度字段最大 4 個字節。

  非規范評注:例如, 十進制數 64 會被編碼為一個字節, 數值是 64, 十六進制表示為 0x40,。十進制數字321(=65+2*128)被編碼為兩個字節, 最低有效位在前。 第一個字節是 65+128=193。 注意最高位為1 表示后面至少還有一個字節。 第二個字節是 2。

  非規范評注:這允許應用發送最大 256MB(268,435,455)大小的控制報文。這個數值在報文中的表示是:0xFF,0xFF,0xFF,0x7F。

  表格  剩余長度字段的大小

  1.2、可變報頭

  可變報文頭主要包含協議名、協議版本、連接標志(Connect Flags)、心跳間隔時間(Keep Alive timer)、連接返回碼(Connect Return Code)、主題名(Topic Name)等。

  某些 MQTT 控制報文包含一個可變報頭部分。 它在固定報頭和負載之間。可變報頭的內容根據報文類型的不同而不同。可變報頭的報文標識符(Packet Identifier) 字段存在於在多個類型的報文里。

  (1) 報文標識符

  (2)遺願標志(Will Flag)

  在可變報文頭的連接標志位字段(Connect Flags)里有三個Will標志位:Will Flag、Will QoS和Will Retain Flag,這些Will字段用於監控客戶端與服務器之間的連接狀況。如果設置了Will Flag,就必須設置Will QoS和Will Retain標志位,消息主體中也必須有Will Topic和Will Message字段。

  那遺願消息是怎么回事呢?服務器與客戶端通信時,當遇到異常或客戶端心跳超時的情況,MQTT服務器會替客戶端發布一個Will消息。當然如果服務器收到來自客戶端的DISCONNECT消息,則不會觸發Will消息的發送。 

  因此,Will字段可以應用於設備掉線后需要通知用戶的場景。

  (3)連接保活心跳機制(Keep Alive Timer)

  MQTT客戶端可以設置一個心跳間隔時間(Keep Alive Timer),表示在每個心跳間隔時間內發送一條消息。如果在這個時間周期內,沒有業務數據相關的消息,客戶端會發一個PINGREQ消息,相應的,服務器會返回一個PINGRESP消息進行確認。如果服務器在一個半(1.5)心跳間隔時間周期內沒有收到來自客戶端的消息,就會斷開與客戶端的連接。心跳間隔時間最大值大約可以設置為18個小時,0值意味着客戶端不斷開。

  1.3、有效載荷(Payload)

  Payload直譯為負荷,可能讓人摸不着頭腦,實際上可以理解為消息主體(body)。

  當MQTT發送的消息類型是CONNECT(連接)、PUBLISH(發布)、SUBSCRIBE(訂閱)、SUBACK(訂閱確認)、UNSUBSCRIBE(取消訂閱)時,則會帶有負荷。

  某些 MQTT 控制報文在報文的最后部分包含一個有效載荷。 對於 PUBLISH 來說有效載荷就是應用消息。

  下面表格包含有效載荷的控制報文 列出了需要有效載荷的控制報文。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM