MQTT抓包分析


1. 概述

MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協議),是一種基於發布/訂閱(Publish/Subscribe)模式的輕量級通訊協議,該協議構建於TCP/IP協議上,由IBM在1999年發布,目前最新版本為v3.1.1。MQTT最大的優點在於可以以極少的代碼和有限的帶寬,為遠程設備提供實時可靠的消息服務。做為一種低開銷、低帶寬占用的即時通訊協議,MQTT在物聯網、小型設備、移動應用等方面有廣泛的應用。眾所周知,TCP/IP參考模型可以分為四層:應用層、傳輸層、網絡層、鏈路層。TCP和UDP位於傳輸層,應用層常見的協議有HTTP、FTP、SSH等。MQTT協議運行於TCP之上,屬於應用層協議,因此只要是支持TCP/IP協議棧的地方,都可以使用MQTT。

2. MQTT客戶端

一個使用MQTT協議的應用程序或者設備,它總是建立到服務器的網絡連接。客戶端可以:
(1)發布其他客戶端可能會訂閱的信息;  //發布消息
(2)訂閱其它客戶端發布的消息;   //訂閱消息
(3)退訂或刪除應用程序的消息;    //退訂消息
(4)斷開與服務器連接。        //斷開,連接服務器

3. MQTT服務器

MQTT服務器以稱為“消息代理”(Broker),可以是一個應用程序或一台設備。它是位於消息發布者和訂閱者之間,它可以:
(1)接受來自客戶的網絡連接;         //接受客戶端連接
(2)接受客戶發布的應用信息;        //接收客戶端發布的消息
(3)處理來自客戶端的訂閱和退訂請求;    //處理消息的訂閱及退訂
(4)向訂閱的客戶轉發應用程序消息。     //推送消息

4. MQTT消息格式

每條MQTT命令消息的消息頭都包含一個固定的報頭,有些消息會攜帶一個可變報文頭和一個負荷。消息格式如下:

固定報文頭 | 可變報文頭 | 負荷

4.1 固定報文頭(Fixed Header)

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

圖4-1固定報頭報文結構
剩余長度字段單個字節最大值為二進制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。

圖4-2數據包類型

圖4-3數據包類型標識位

4.2 可變報文頭(Variable Header)

可變報文頭主要包含協議名、協議版本、連接標志(Connect Flags)、心跳間隔時間(Keep Alive timer)、連接返回碼(Connect Return Code)、主題名(Topic Name)等,后面會針對主要部分進行講解。

圖4-4可變報頭結構

4.2.1 消息質量(QoS)

MQTT消息質量有三個等級,QoS 0,QoS 1和 QoS 2。
QoS 0:最多分發一次。消息的傳遞完全依賴底層的TCP/IP網絡,協議里沒有定義應答和重試,消息要么只會到達服務端一次,要么根本沒有到達。
QoS 1:至少分發一次。服務器的消息接收由PUBACK消息進行確認,如果通信鏈路或發送設備異常,或者指定時間內沒有收到確認消息,發送端會重發這條在消息頭中設置了DUP位的消息。
QoS 2:只分發一次。這是最高級別的消息傳遞,消息丟失和重復都是不可接受的,使用這個服務質量等級會有額外的開銷。

4.2.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字段可以應用於設備掉線后需要通知用戶的場景。

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

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

4.3 有效負荷(Payload)

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

圖4-5消息結構

當MQTT發送的消息類型是CONNECT(連接)、PUBLISH(發布)、SUBSCRIBE(訂閱)、SUBACK(訂閱確認)、UNSUBSCRIBE(取消訂閱)時,則會帶有負荷。
(1)CONNECT,消息體內容主要是:客戶端的ClientID、訂閱的Topic、Message以及用戶名和密碼。
(2)SUBSCRIBE,消息體內容是一系列的要訂閱的主題以及QoS。
(3)SUBACK,消息體內容是服務器對於SUBSCRIBE所申請的主題及QoS進行確認和回復。
(4)UNSUBSCRIBE,消息體內容是要訂閱的主題。
(5)PUBLISH,消息體內容是相關主題的數據。

5. MQTT控制報文

介紹MQTT協議的報文組成並通過wireshark抓取報文包分析報文內容

5.1 連接服務端(CONNECT)

Connect報文在MQTT客戶端連接服務器時發出,報文由三部分組成,下面將分別介紹

5.1.1 固定報頭(fixed header)

圖5-1 CONNECT固定報頭報文

Connect名稱的值為1,低四位保留,剩余長度保存可變報頭(10字節)加上有效載荷的長度。

5.1.2 可變報頭(variable header)

Connect報文的可變報頭包含協議名,協議等級,連接標志和保持連接

圖5-2 CONNECT可變報頭報文

報文協議名之前有兩個字節的報文標識符,唯一標識這條報文。

連接標志包含用戶名標志(username flag)、密碼標志(password flag)、遺囑標志(will flag)、遺囑服務指令(will Qos)、遺囑保留標志(will retain)、清除會話標志(clean session)、保留位(reserved)。
用戶名標志(username flag):若用戶名標志被置為1,有效載荷中必須包含用戶名字段。
密碼標志(password flag):若密碼標志被置為1,有效載荷中必須包含密碼字段,當用戶標志被置為0時,密碼標志必須被置0.。
遺囑標志(will flag):若遺囑標志被置1,遺囑服務指令(will Qos)與遺囑保留標志(will retain)會被服務器用到,遺囑消息中必須包含will topic和will message。
遺囑服務指令(will Qos):如果遺囑標志被設置為0,遺囑QoS也必須設置為0(0x00),如果遺囑標志被設置為1,遺囑QoS的值可以等於0(0x00),1(0x01),2(0x02)。它的值不能等 於3。
遺囑保留標志(will retain):若遺囑保留標志位被置位,服務器將保留遺囑消息(保留發布),當客戶端異常斷開連接時將遺囑發給訂閱遺囑主題的客戶。
清除會話標志(clean session):標志被設置為1,客戶端和服務端必須丟棄之前的任何會話並開始一個新的會話(之前的訂閱與發布消息被刪除),若標志為0,恢復與服務器會話連接,若沒有連接 新建一個會話連接(不刪除之前與客戶端的會話信息並保存斷開本次會話之后的Qos1與Qos2消息)。
保留位(reserved):如果不為0必須斷開客 戶端連接。

報文最后兩字節為發送心跳包的間隔時間,當客戶端沒有數據發給服務器時,須發送心跳包(pingreq)到服務器,保證連接不斷開。

5.1.3 有效載荷(Payload)

CONNECT報文的有效載荷(payload)包含一個或多個以長度為前綴的字段,可變報頭中的 標志決定是否包含這些字段。如果包含的話,必須按這個順序出現:客戶端標識符,遺囑主題,遺囑消息,用戶名,密碼。
客戶端標識符(client identifier):服務器通過識別客戶標識符,確定客戶端,識別兩者間的MQTT會話相關狀態,服務器允許客戶端提供一個零字節的標識符,但clean session必須置1。

圖5-3 CONNECT消息報文

5.2連接請求確認(CONNACK)

Connack為服務器確認客戶端連上服務給出的回應。

5.2.1 固定報頭(fixed header)

圖5-4 CONNACK固定報頭報文

5.2.2 可變報頭(variable header)

圖5-5 CONNACK可變報頭報文
  • 第一字節1~7位保留,第0位是當前會話標志(session present),若清除會話標志被置1,該位為0,若清除會話標志為0且服務器沒有與客戶端會話保存,該位置0,有保存置1 第二字節保存連接返回碼,若連接成功返回0。
  • 圖5-6 連接返回碼

    圖5-7 CONNECT響應報文

    5.3發布消息(PUBLISH)

    發布消息可由客戶端或服務器發出,被消息訂閱者接收。

    5.3.1 固定報頭(fixed header)

    圖5-8 PUBLISH固定報頭報文

    固定報頭第一字節的低四位分別保存重發標志(DUP),服務質量(Qos),保留標志(RETAIN)。
    重發標志(DUP):當該位被置1,表示該條報文為重發報文,客戶端或服務端請求重發一個PUBLISH報文時,必須將DUP標志設置為1。對於QoS 0的消息,DUP標志必須設置為0。
    服務質量(Qos):表示發送質量,取值有00 01 10。
    保留標志(RETAIN):若該位被置1,表示服務器必須保存其應用消息和質量等級,若為0,表示該消息不須保存,如果服務端收到一條保留(RETAIN)標志為1的QoS 0消息,它必須丟棄之前為那個主題保留的任何消息。它應該將這個新的QoS0消息當作那個主題的新保留消息,但是任何時候都可以選擇丟棄它,保留標志為1且有效載荷為零字節的PUBLISH報文會被服務端當作正常消息處理,它會被發送給訂閱主題匹配的客戶端。此外,同一個主題下任何現存的保留消息必須被移除,因此這個主題之后的任何訂閱者都不會收到一個保留消息。

    5.3.2 可變報頭(variable header)

    可變報頭按順序包含主題名和報文標識符。

    5.3.3 有效載荷(Payload)

    若Qos為0,無響應,若Qos為1,返回PUBACK報文,若Qos為2,返回PUBREC報文。

    圖5-9 publish消息報文

    5.4發布確認(PUBACK)

    由服務器或客戶端確認已接收到pub消息

    5.4.1 固定報頭(fixed header)

    圖5-10 puback固定報頭報文

    5.4.2 可變報頭(variable header)

    只有兩字節的報文標識(報文標識為pub報文標識)

    圖5-11 puback消息報文

    5.5發布收到 PUBREC(QoS 2,第一步)

    5.5.1 固定報頭(fixed header)

    圖5-12 pubrec固定報頭報文

    5.5.2 可變報頭(variable header)

    只有兩字節的報文標識(報文標識為pub報文標識)

    圖5-13 pubrec消息報文

    5.6發布釋放 PUBREL(QoS 2,第二步)

    5.6.1 固定報頭(fixed header)

    圖5-14 pubrel固定報頭報文

    5.6.2 可變報頭(variable header)

    只有兩字節的報文標識(報文標識為pub報文標識)

    圖5-15 pubrel消息報文

    5.7發布完成 PUBCOMP(QoS 2,第三步)

    5.7.1 固定報頭(fixed header)

    圖5-16 pubcomp固定報頭報文

    5.7.2 可變報頭(variable header)

    只有兩字節的報文標識(報文標識為pub報文標識)

    圖5-17 pubcomp消息報文

    5.8訂閱主題(SUBSCRIBE)

    客戶端通過訂閱消息的方式來接收服務端下發的消息

    5.8.1 固定報頭(fixed header)

    SUBSCRIBE控制固定報頭的第3,2,1,0位是保留位,必須分別設置為0,0,1,0。服務端必須將其它的任何值都當做是不合法的並關閉網絡連接

    圖5-18 subscribe固定報頭報文

    5.8.2 可變報頭(variable header)

    只有兩字節的報文標識

    5.8.3 有效載荷(Payload)

    圖5-19 subscribe有效載體報文

    消息載體包含若干主題過濾器和服務質量等級
    PUB時指定的qos是服務器肯定按此規則接收,但是最終訂閱者不一定。
    SUB時指定的qos表示訂閱者可以接收的最高消息等級,也就是可能收到更低等級的消息

    圖5-20 subscribe消息報文

    5.9訂閱確認(SUBACK)

    SUBACK報文包含一個返回碼清單,它們指定了SUBSCRIBE請求的每個訂閱被授予的最大QoS等級。

    5.9.1 固定報頭(fixed header)

    圖5-21 suback固定報頭報文

    5.9.2 可變報頭(variable header)

    只有兩字節的報文標識

    5.9.3 有效載荷(Payload)

    圖5-22 suback有效載體報文

    允許的返回碼為0x00-最大Qos0,0x01-最大Qos1,0x02-最大Qos2,0x80-失敗

    圖5-23 suback消息報文

    5.10取消訂閱 (UNSUBSCRIBE)

    5.10.1 固定報頭(fixed header)

    圖5-24 unsubscribe固定報頭報文

    5.10.2 可變報頭(variable header)

    只有兩字節的報文標識

    5.10.3 有效載荷(Payload)

    包含需要取消訂閱的主題過濾器的列表.

    圖5-25 unsubscribe消息報文

    5.11取消訂閱確認 (UNSUBACK)

    5.11.1 固定報頭(fixed header)

    圖5-26 unsuback固定報頭報文

    5.11.2 可變報頭(variable header)

    只有兩字節的報文標識(報文標識為unsub報文標識)

    圖5-27 unsuback消息報文

    5.12心跳請求 (PINGREQ)

    客戶端發送PINGREQ報文給服務端的。用於:
    1.在沒有任何其它控制報文從客戶端發給服務的時,告知服務端客戶端還活着。
    2.請求服務端發送 響應確認它還活着。
    3.使用網絡以確認網絡連接沒有斷開

    5.12.1 固定報頭(fixed header)

    圖5-28 pingreq固定報頭報文

    圖5-29 pingreq消息報文

    5.13心跳響應 (PINGRESP)

    5.13.1 固定報頭(fixed header)

    圖5-30 pingresp固定報頭報文

    圖5-31 pingresp消息報文

    5.14斷開連接 (DISCONNECT)

    5.14.1 固定報頭(fixed header)

    圖5-32 disconnect固定報頭報文

    圖5-33 disconnect消息報文

    抓包注意:用標准不加密MQTT能抓到便於查看的報文,加密報文解析時不便於理解

    創作不易,白嫖不好,各位的支持和認可,就是我創作的最大動力,我們下篇文章見!

    清風 | 文 【原創】

    如果本篇博客有任何錯誤,請批評指教,不勝感激 !


    免責聲明!

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



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