轉戰物聯網·基礎篇07-深刻理解MQTT協議之控制報文(數據包)格式

  在MQTT協議中,一個控制報文(數據包)的結構按照先後順序分以下三部分:網絡

結構名 中文名 解釋說明
Fixed header 固定報頭 報文的最開始部分,全部報文都包含這個部分
Variable header 可變報頭 固定報文的附加部分,有些報文沒有這個部分
Payload 有效載荷 須要攜帶的信息內容,有些報文沒有這個部分

  下圖是MQTT控制報文(數據包)格式的結構示意圖:
ide

一、固定報頭(Fixed header):

  固定報頭存在於全部MQTT數據包中,表示數據包類型及控制類標誌等。固定報頭由至少2個字節組成,格式以下:編碼

Bit(位號) 7 6 5 4 3 2 1 0
Byte1(第一個字節) 組合表明MQTT控制報文(數據包)的類型 控制報文的標誌位(Flags),可理解爲一種屬性參數
Byte2(第二個字節起) 剩餘長度,當前報文剩餘部分的字節數,包括可變報頭和有效負載

1.一、控制報文類型(Control Packet type):

  固定報頭第一個字節的高四位(7-4號位)是表明控制報文的類型,也就是這個數據包是作什麼用的。是用7-4號位的二進制(也就是1111--0000之間)組合值,來表明具體的含義,見下表:spa

7-4號位 十進制值 報文類型 報文容許發起方向 報文描述
0000 0 Reserved 禁止 保留,不可用
0001 1 CONNECT 客戶端―→服務端 客戶端請求鏈接到服務端的代理服務
0010 2 CONNACK 客戶端←―服務端 鏈接請求的回覆確認報文
0011 3 PUBLISH 客戶端←→服務端 發佈主題消息
0100 4 PUBACK 客戶端←→服務端 發佈確認,是QoS=1時,對 PUBLISH 的響應確認
0101 5 PUBREC 客戶端←→服務端 發佈收到,是QoS=2時,對 PUBLISH 的響應確認,是QoS=2實現的第一步
0110 6 PUBREL 客戶端←→服務端 發佈釋放,是QoS=2時,對 PUBREC 的響應確認,是QoS=2實現的第二步
0111 7 PUBCOMP 客戶端←→服務端 發佈完成,是QoS=2時,對 PUBREL 的響應確認,是QoS=2實現的第三步
1000 8 SUBSCRIBE 客戶端―→服務端 客戶端訂閱主題,可一次訂閱一個或多個主題(使用通配符)
1001 9 SUBACK 客戶端←―服務端 訂閱完成確認,是對 SUBSCRIBE 的響應確認
1010 10 UNSUBSCRIBE 客戶端―→服務端 取消訂閱,客戶端發起的取消對某個主題的訂閱
1011 11 UNSUBACK 客戶端←―服務端 取消訂閱確認,是對 UNSUBSCRIBE 的響應確認
1100 12 PINGREQ 客戶端―→服務端 心跳,表示這個數據包是爲通知服務端客戶端還在正常鏈接着
1101 13 PINGRESP 客戶端←―服務端 心跳響應,表示服務端已經成功收到了客戶端的心跳
1110 14 DISCONNECT 客戶端―→服務端 斷開鏈接,客戶端通知服務端,須要斷開當前網絡鏈接
1111 15 Reserved 禁止 保留,不可用

1.二、標誌(Flags):

  固定報頭第1個字節的低4位 (3-0號位)包含每一個MQTT控制報文類型特定的標誌,必須與控制報文類型配套對應使用,不然服務端代理服務會拒絕服務或斷開鏈接。具體的見下表(保留的標誌必須按照表中的值設置):代理

報文類型 標誌類型 Bit3 Bit2 Bit1 Bit0
CONNECT 保留 0 0 0 0
CONNACK 保留 0 0 0 0
PUBLISH 使用 是否爲重複發 服務質量高位 服務質量低位 是否保存消息
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

  注:關於用「是否」描述的實際就是布爾類型,0表示否,1表示是;blog

1.三、第一字節各種型報文具體值:

  固定報頭報文類型高4位和標誌位的低4位綜合起來,最終第一個字節是有一個具體值的。爲了更好的理解第一個字節的具體值是怎樣得出來的,在下表列出了不一樣類型的報文及某個報文不一樣標誌時的具體值:rem

報文類型 標誌做用 二進制值 10進制值 16進制值
CONNECT 鏈接服務端 00010000 16 0x10
CONNACK 鏈接成功確認 00100000 32 0x20
PUBLISH 新發布等級0不保存 00110000 48 0x30
PUBLISH 新發布等級0需保存 00110001 49 0x31
PUBLISH 新發布等級1不保存 00110010 50 0x32
PUBLISH 新發布等級1需保存 00110011 51 0x33
PUBLISH 新發布等級2不保存 00110100 52 0x34
PUBLISH 新發布等級2需保存 00110001 53 0x35
PUBLISH 重發等級2不保存 00111000 56 0x38
PUBLISH 重發等級2需保存 00111001 57 0x39
PUBACK 等級1發佈成功 01000000 64 0x40
PUBREC 等級2發佈收到 01010000 80 0x50
PUBREL 等級2發佈釋放 01100010 98 0x62
PUBCOMP 等級2發佈完成 01110000 112 0x70
SUBSCRIBE 訂閱主題 10000010 130 0x82
SUBACK 訂閱完成確認 10010000 144 0x90
UNSUBSCRIBE 取消訂閱 10100010 162 0xA2
UNSUBACK 取消完成確認 10110000 176 0xB0
PINGREQ 心跳包 11000000 192 0xC0
PINGRESP 心跳回復 11010000 208 0xD0
DISCONNECT 斷開網絡鏈接 11100000 224 0xE0

  注:關於發佈主題還有其餘狀況這裏就沒有所有列出,根據表中的規律就能夠計算出實際的值了。it

1.三、剩餘長度(Remaining Length):

  剩餘長度是從第二個字節開始,最多容許佔用四個字節。描述本次傳送的應用消息在剩餘長度字節以後(不包括剩餘長度字節自己)還有多少個字節,包括可變報頭(有的報文沒有這部分) + 有效載荷(有的報文沒有這部分)的全部字節數量。table

  根據上面描述,剩餘長度屬於變長的編碼規則,也就是它多是1-4個字節中的任何一種狀況,那麼怎樣知道當前這個報文的剩餘長度是佔用了幾個字節的呢?若是不能肯定,那麼接收方就沒法正確解析數據了。因此MQTT協議規定剩餘長度的每一個字節的最高位(也就是7號位)做爲是否還有下一個字節剩餘長度的標誌位,不作長度數值的表述位。這樣每給剩餘長度字節最大表明長度值就是127(二進制 1111111 的值)了,由於只有7個位表示長度了。向後每增長一個字節都表明前一個字節滿值再加1的倍數,四個字節的剩餘長度表明的長度值最大可爲268435455。class

  若是剩餘長度值不大於127,則只用一個字節表示,例如121,則剩餘長度字節的二進制是01111001,含義見下表:

7號位 6-0號位
0 1111001
接下來沒有剩餘長度字節了 剩餘長度是:121

  若是剩餘長度值大於127小於16384,則需用兩個字節表示,例如15971,則剩餘長度兩字節具體值則是0xE3 0x7C(11100011 01111100),含義見下表:

1字節7號位 1字節6-0號位 2字節7號位 2字節6-0號位
1 1100011 0 1111100
後面還有字節描述長度 本子節描述長度:99 後面沒有長度字節了 本字節描述長度:124 * 128 = 15872

  兩個字節表明的長度值相加 99 + 15872 = 15971,這既是完整的剩餘長度值了。後面這個字節每增長1,則表明剩餘長度值增長128。也就是前面字節的低7位值滿都爲1(127)再加1,就到後面字節加1,前面字節低7位歸0。再加滿再到後面字節加1,以此類推。因此兩個字節能夠表述的最大值是(11111111 01111111)127+(127*128) = 16383。
  因爲使用了兩個字節表述剩餘長度,那麼前面的字節的最高位7號位就要置1,以告訴解析程序後面的字節還要按照剩餘長度來計算。

  若是剩餘長度值大於16383小於2097152,則需用三個字節表示,例如2097150,則剩餘長度三字節具體值則是0xFE 0xFF 0x7F(11111110 11111111 01111111),含義見下表:

1字節7號位 1字節6-0號位 2字節7號位 2字節6-0號位 3字節7號位 3字節6-0號位
1 1111110 1 1111111 0 1111111
還有長度字節 長度:126 還有長度字節 長度:127 * 128 = 16256 長度最後字節 長度:127 * 16384 = 2080768

  三個字節表明的長度值相加 126 + 16256 + 2080768 = 2097150,這既是完整的剩餘長度值了。3字節每增長1,則表明剩餘長度值增長16384,即前兩個字節滿值再加1。四字節的原理也是這樣向後推導,這裏就再也不列舉了。

  剩餘長度使用1-4個字節能夠描述的長度範圍見下表:

字節數 最小值10/16進制 最小值2進制 最大值10/16進制 最大值2進制
1 0(0x00) 00000000 127(0x7F) 01111111
2 128(0x80,0x01) 10000000 00000001 16383(0xFF,0x7F) 11111111 01111111
3 16384(0x80,0x80,0x01) 10000000 10000000 00000001 2097151(0xFF,0xFF,0x7F) 11111111 11111111 01111111
4 2097152(0x80,0x80,0x80,0x01) 10000000 10000000 10000000 00000001 268435455(0xFF,0xFF,0xFF,0x7F) 11111111 11111111 11111111 01111111

二、可變報頭(Variable header):

  可變報頭在固定報頭與有效負載之間,不是全部的報文都有可變報頭。報文類型不一樣可變報頭的內容也不一樣。後面會對各報文的可變報頭逐一討論。某些類型的報文中的可變報頭還包含報文標識符(Packet Identifier)字段。

2.一、報文標識符(Packet Identifier):

  報文標識符,必定程度上至關因而每一個報文的惟一ID,用於識別報文身份的。重複發送報文時,必須使用相同的報文標識符。在須要應答的控制報文裏,標識符能夠區分是應答的哪一個報文。某些控制報文的可變報頭部分包含一個兩字節的報文標識符字段。這些報文分別是PUBLISH(QoS > 0時), PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE, SUBACK,UNSUBSCRIBE,UNSUBACK。
  須要使用標識符的報文,發送方在每次發送一個新的報文時,必須分配一個沒有使用過的報文標識符。報文標識符固定使用兩個字節,按照雙字節讀值可用範圍是0-65535(00000000 00000000 -- 11111111 11111111)。

三、有效載荷(Payload):

在一些須要攜帶用戶自定義的應用消息的MQTT控制報文中,會將這些信息放在報文的最後部分,稱之爲有效載荷。對於PUBLISH來講有效載荷就是應用消息。不一樣的控制報文有效載荷內容不一樣,後面會在分別介紹控制報文時具體討論。下表列出哪些控制報文有包含有效載荷:

控制報文 有效載荷
CONNECT 須要
CONNACK 不 須要
PUBLISH 可選,能夠零長度
PUBACK 不須要
PUBREC 不須要
PUBREL 不須要
PUBCOMP 不須要
SUBSCRIBE 須要
SUBACK 須要
UNSUBSCRIBE 須要
UNSUBACK 不須要
PINGREQ 不須要
PINGRESP 不須要
DISCONNECT 不須要

  本節完,待續......

相關文章
相關標籤/搜索