在上一篇文章,直接在本地搭建了服務器和客戶端,簡單的實踐了MQTT的用法。而這一篇來解析MQTT的報文格式。MQTT的報文字段很精簡。但是解析起來還是有些復雜的。
解析報文最好的工具是采用wireshark抓包,不過我發現,wireshark的2.xxx的版本無法進行回環抓包(即無法抓取127.0.0.1的數據報文)。通過一番度娘,發現新版本的wireshark用Npcap替換WinPcap,Npcap是基于WinPcap 4.1.3開發的,api兼容WinPcap。
030
MQTT報文
MQTT報文格式
MQTT的報文字段主要包含3部分,如下表:
名稱 | 說明 |
---|---|
Fixed header(固定報文頭) | 所有MQTT報文都包含 |
Variable header(可變報文頭) | 只有部分MQTT報文包含 |
Payload(MQTT數據段) | 只有部分MQTT報文包含 |
MQTT固定報文頭[Fixed header]
每個MQTT報文都包含一個固定報文頭,固定報文頭部格式如下:
bit76543210 +-----+-----+-----+-----+-----+-----+-----+-----+-----+ |Byte1|MQTT控制報文類型|指定控制報文類型的標志| +-----+-----------------------------------------------| |Byte2|剩余長度| +-----+-----------------------------------------------| |...|剩余長度| +-----------------------------------------------------|
MQTT控制報文類型
MQTT的控制報文類型在固定報文頭的第1個字節的4 ~ 7bit,共4位無符號值。這些值如下表描述:
類型 | 值 | 報文方向 | 描述 |
---|---|---|---|
RESERVED | 0 | 禁止 | 保留 |
CONNECT | 1 | 客戶端到服務端 | 客戶端請求連接服務器 |
CONNACK | 2 | 服務端到客戶端 | 連接報文確認 |
PUBLISH | 3 | 雙向 | 發布消息 |
PUBACK | 4 | 雙向 | QoS 1消息發布收到確認 |
PUBREC | 5 | 雙向 | 發布收到(保證交付第一步) |
PUBREL | 6 | 雙向 | 發布釋放(保證交付第二步) |
PUBCOMP | 7 | 雙向 | QoS 2消息發布完成 |
SUBSCRIBE | 8 | 客戶端到服務端 | 客戶端訂閱請求 |
SUBACK | 9 | 服務端到客戶端 | 訂閱請求報文確認 |
UNSUBSCRIBE | 10 | 客戶端到服務端 | 客戶端取消訂閱請求 |
UNSUBACK | 11 | 服務端到客戶端 | 取消訂閱請求報文確認 |
PINGREQ | 12 | 客戶端到服務端 | 心跳請求 |
PINGRESP | 13 | 服務端到客戶端 | 心跳響應 |
DISCONNECT | 14 | 客戶端到服務端 | 客戶端斷開連接 |
RESERVED | 15 | 禁止 | 保留 |
MQTT控制報文標志
MQTT的控制報文標志在固定報文頭的第1個字節的4 ~ 7bit,包含每個MQTT報文類型的特定的標志。
注意:如果接收方收到非法的標志,接受者必須關閉網絡連接。標志如下表:
其中:
DUP:控制報文的重復分發標志
QoS:PUBLISH報文的服務質量等級
RETAIN:PUBLISH報文的保留標志
類型 | 報文標志 | Bit3 | Bit2 | Bit1 | Bit0 |
---|---|---|---|---|---|
CONNECT | Reserved | 0 | 0 | 0 | 0 |
CONNACK | Reserved | 0 | 0 | 0 | 0 |
PUBLISH | Used in MQTT 3.1.1 | DUP | QoS | QoS | RETAIN |
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 |
MQTT報文剩余長度
剩余長度字段從固定報文頭的第2個字節開始,最長可達4個字節,所以剩余長度訪問是Byte[2 ~ 5]。
剩余長度表示當前報文剩余部分的字節數,包含可變頭部和Payload。
上面的描述,那么怎么確定其長度用幾個字節來描述呢?答案:取決于字節的最高位Bit7(默認都是在搞自己在前);如果Bit7為1,那么需要繼續計算字節長度,如果Bit7為0,那么不需要繼續計算字節長度。
消息長度可以簡單理解為128禁止的數據,4位長度最大可以表示:128 * 128 * 128 * 128 Byte = 256MB。
需注意計算規則,低位在前,高位在后,字節最高位Bit7標記是否繼續計算消息長度。其消息長度范圍如下表:
字節 | 最小值 | 最大值 |
---|---|---|
1 | 0(0x00) | 127(0x7F) |
2 | 128(0x80, 0x01) | 16383(0xFF, 0X7F) |
3 | 16384(0x80, 0x80, 0x01) | 2097151(0xFF, 0xFF, 0x7F) |
4 | 2097152(0x80, 0x80, 0x80, 0x01) | 268435455(0xFF, 0xFF, 0xFF, 0x7F) |
舉例:
第一字節最高位是1,需要繼續向后計算,去掉標記位(0xC1%128),得到1000001=41
第二字節最高位是1,需要繼續向后計算,去掉標記位(0xC2%128),得到1000010=42
第三字節最高位是0,不需要向后計算,其結果就是0x33=51
因為低位在前,高位在后,即消息長度為:41 + 42 * 128 + 51 * 128 * 128=841001Byte = 821KB
0xC1 = 11000001
0xC2 = 11000010
0x33 = 00110011
消息長度是0x60,其二進制是01100000b,字節最高位Bit7位0,所以不需要往后計算,其十進制是96(即消息長度為96個字節)。
消息長度是0xC1, 0xC2, 0x33。分別二進制為:
MQTT可變報文頭[Variable header]
在某些MQTT控制報文包含了一個可變報文頭部分,它在固定報文頭和payload之間,可變報頭的內容根據報文類型的不同而不同,可變報頭的報文標識符(Packet Identifier)字段存在與多個類型的報文里。可變報頭其實就是MQTT開發中使用的Packet ID,通過Packet ID 進行一些操作確認。包含Packet ID的報文類型如下:
類型 | 包含可變報文頭 |
---|---|
PUBLISH | √(QoS > 0) |
PUBACK | √ |
PUBREC | √ |
PUBREL | √ |
PUBCOMP | √ |
SUBSCRIBE | √ |
SUBACK | √ |
UNSUBSCRIBE | √ |
UNSUBACK | √ |
Packet ID默認是從1開始并自增,如果一個Packet ID被用完后,這個Packet ID可以被重用。對于PUBLISH(QoS 1)來說,如果發送端接收到PUBACK,那么這個Packet ID就用完了。對于PUBLISH(QoS 2),如果接收方收到PUBCOMP,那么這個Packet ID就用完了。對于SUBSCRIBE和UNSUBSCRIBE,Packet ID使用完成的標記是發送方收到了對應的SUBACK和UNSUBACK。
MQTT數據段[Payload]
MQTT中有些報文類型是包含Payload
如PUBLISH的Payload指消息內容。
如CONNECT的Payload指Client Identifier,Will Topic,Will Message,Username,Password等信息
包含Payload的報文類型如下:
類型 | 包含Payload |
---|---|
CONNECT | √ |
PUBLISH | 可選 |
SUBSCRIBE | √ |
SUBACK | √ |
UNSUBSCRIBE | √ |
通過wireshark分析MQTT報文
因為我們的服務器和客戶端是在PC上搭建的,所以需要通過wireshark的回環抓包,來分析報文類型CONNECT和CONNACK。
打開wireshark,選擇進行回環抓包
使用MQTT.fx創建一個客戶端,點擊連接,便可以抓到CONNECT和CONNACK的報文。
紅色圈子的報文類型CONNECT的內容:
內容: 1025 00044d515454 04 c2 003c 0008636c69656e743031 000561646d696e 00083132333435363738
報文類型CONNECT內容分析:
0x10:高四位0001,代表報文類型:CONNECT。
0x25:二進制-0010 0101,Bit7為0,所以剩余長度只有一個字節長,即0x25十進制:37個字節
0x00 0x04 0x4d 0x51 0x54 0x54:其中-0x00,0x04表示協議長度;0x4d 0x51 0x54 0x54對應 "M", "Q", "T", "T"。
0x04:代表MQTT版本號:v3.1.1
0xc2: 次字節含義如下表,該字節描述緊跟數據有 User Name、Password,沒有遺囑設置,選擇了清理會話方式與服務器連接。
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
含義 | User Name Flag | Password Flag | Will Retain Flag | Will QoS MSB | Will QoS LSB | Will Flag | Clean session | Rreserved |
值 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
00 3c:對應十進制為60,即保持連接(Keep Alive)60秒,以秒為單位,它是指在客戶端傳輸完成一個控制報文的時刻到發送下一個報文的時刻,兩者之間允許空閑的最大時間間隔。客戶端負責保證控制報文發送的時間間隔不超過保持連接的值。如果沒有任何其它的控制報文可以發送,客戶端 必須發送一個PINGREQ 報文。客戶端隨時可以發送ping指令,服務器如果發現在KeepAalive時間內沒有收到客戶端的消息,會自動斷開與客戶端建立的連接。
00 08 63 6c 69 65 6e 74 30 31:其中-0x00, 0x08表示clientID的長度8個字節;0x63,0x6c,0x69,0x65,0x6e,0x74,0x30,0x31:代表client01。即是我們在MQTT.fx創建客戶端的時候設置clientID。
00 05 61 64 6d 69 6e:其中-0x00,0x05表示User Name的的長度5個字節;0x61,0x64,0x6d,0x69,0x6e:代表User Name為admin,即是我們在MQTT.fx創建客戶端的時候設置User Name。
00 08 31 32 33 34 35 36 37 38:其中-0x00,0x08表示User Name的的長度8個字節;0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38:代表Password為12345678,即是我們在MQTT.fx創建客戶端的時候設置Password。
紅色圈子的報文類型CONNACK的內容:
內容: 20 02 00 00
報文類型CONACK內容分析:
20:高四位0010,代表報文類型:CONNACK。
02:二進制-0000 0010,Bit為0,所以剩余長度只有一個字節長,即0x02十進制:2個字節。
00:可變頭部的第一個字節的第0位連接確認。
00:可變頭部的第二個字節。
值 | 返回碼響應 | 描述 |
---|---|---|
0 | 0x00連接已接受 | 連接已被服務器接受 |
1 | 0x01連接已拒絕,不支持的協議版本 | 服務器不支持客戶端請求的協議版本 |
2 | 0x02連接已拒絕,不合格的客戶端ID | 客戶端ID是正確的UTF-8碼,但服務器不允許使用 |
3 | 0x03連接已拒絕,服務端不可用 | 網絡連接已建立,但MQTT服務不可用 |
4 | 0x04連接已拒絕,無效的用戶名或密碼 | 用戶名或密碼的數據格式無效 |
5 | 0x05連接已拒絕,未授權 | 客戶端未被授權連接到此服務器 |
6-255 | Reserved | 保留 |
原文標題:教你動手寫網絡協議棧-MQTT報文解析6-解析
文章出處:【微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。
-
網絡
+關注
關注
14文章
7599瀏覽量
89243 -
報文數據
+關注
關注
0文章
3瀏覽量
7660
原文標題:教你動手寫網絡協議棧-MQTT報文解析6-解析
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
百問MQTT協議分析 - 報文分析①
百問MQTT協議分析 - MQTT簡述及協議報文格式組成
MQTT協議網關的工作原理及功能特性
![<b class='flag-5'>MQTT</b><b class='flag-5'>協議</b>網關的工作原理及功能特性](https://file1.elecfans.com//web2/M00/07/B1/wKgaombqlp6ARrPnAADgy2-cZI8853.jpg)
基于MQTT協議云平臺的Modbus轉MQTT網關
![基于<b class='flag-5'>MQTT</b><b class='flag-5'>協議</b>云平臺的Modbus轉<b class='flag-5'>MQTT</b>網關](https://file1.elecfans.com/web2/M00/00/11/wKgaomanYQ6ARFCfAAAaWpcP9_Y947.png)
如何通過北向MQTT自定義報文格式對接到物聯網云平臺
![如何通過北向<b class='flag-5'>MQTT</b>自定義<b class='flag-5'>報文格式</b>對接到物聯網云平臺](https://file1.elecfans.com//web2/M00/EC/25/wKgaomZdiKWAF76SAAPVgT1WpFg398.png)
modbus報文解析,modbus報文格式詳解
CAN的報文格式和發送總流程
![CAN的<b class='flag-5'>報文格式</b>和發送總流程](https://file1.elecfans.com/web2/M00/C8/CA/wKgaomYXRmuADYBxAAAaELp1sQA288.png)
評論