在MQTT協議中,一個控制報文(數據包)的結構按照先後順序分以下三部分:網絡
結構名 | 中文名 | 解釋說明 |
---|---|---|
Fixed header | 固定報頭 | 報文的最開始部分,全部報文都包含這個部分 |
Variable header | 可變報頭 | 固定報文的附加部分,有些報文沒有這個部分 |
Payload | 有效載荷 | 須要攜帶的信息內容,有些報文沒有這個部分 |
下圖是MQTT控制報文(數據包)格式的結構示意圖:
ide
固定報頭存在於全部MQTT數據包中,表示數據包類型及控制類標誌等。固定報頭由至少2個字節組成,格式以下:編碼
Bit(位號) | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
Byte1(第一個字節) | 組合表明MQTT控制報文(數據包)的類型 | 控制報文的標誌位(Flags),可理解爲一種屬性參數 | ||||||
Byte2(第二個字節起) | 剩餘長度,當前報文剩餘部分的字節數,包括可變報頭和有效負載 |
固定報頭第一個字節的高四位(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個字節的低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
固定報頭報文類型高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
剩餘長度是從第二個字節開始,最多容許佔用四個字節。描述本次傳送的應用消息在剩餘長度字節以後(不包括剩餘長度字節自己)還有多少個字節,包括可變報頭(有的報文沒有這部分) + 有效載荷(有的報文沒有這部分)的全部字節數量。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 |
可變報頭在固定報頭與有效負載之間,不是全部的報文都有可變報頭。報文類型不一樣可變報頭的內容也不一樣。後面會對各報文的可變報頭逐一討論。某些類型的報文中的可變報頭還包含報文標識符(Packet Identifier)字段。
報文標識符,必定程度上至關因而每一個報文的惟一ID,用於識別報文身份的。重複發送報文時,必須使用相同的報文標識符。在須要應答的控制報文裏,標識符能夠區分是應答的哪一個報文。某些控制報文的可變報頭部分包含一個兩字節的報文標識符字段。這些報文分別是PUBLISH(QoS > 0時), PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE, SUBACK,UNSUBSCRIBE,UNSUBACK。
須要使用標識符的報文,發送方在每次發送一個新的報文時,必須分配一個沒有使用過的報文標識符。報文標識符固定使用兩個字節,按照雙字節讀值可用範圍是0-65535(00000000 00000000 -- 11111111 11111111)。
在一些須要攜帶用戶自定義的應用消息的MQTT控制報文中,會將這些信息放在報文的最後部分,稱之爲有效載荷。對於PUBLISH來講有效載荷就是應用消息。不一樣的控制報文有效載荷內容不一樣,後面會在分別介紹控制報文時具體討論。下表列出哪些控制報文有包含有效載荷:
控制報文 | 有效載荷 |
---|---|
CONNECT | 須要 |
CONNACK | 不 須要 |
PUBLISH | 可選,能夠零長度 |
PUBACK | 不須要 |
PUBREC | 不須要 |
PUBREL | 不須要 |
PUBCOMP | 不須要 |
SUBSCRIBE | 須要 |
SUBACK | 須要 |
UNSUBSCRIBE | 須要 |
UNSUBACK | 不須要 |
PINGREQ | 不須要 |
PINGRESP | 不須要 |
DISCONNECT | 不須要 |
本節完,待續......