MQTT協議探究(一)

1 準備階段

2 MQTT控制報文格式

2.1 MQTT控制報文結構

  • 固定報頭,全部控制報文都包含
  • 可變報頭,部分控制報文包含
  • 有效負載,部分控制報文包含

2.2 固定報頭

Bit 7 6 5 4 3 2 1 0
byte 1 MQTT 控制報文的類型 用於指定控制報文類型的標誌符
byte 2 剩餘長度(可變報頭長度 + 有效負載長度)

(1)MQTT控制報文的類型

  • 僅顯示部分,具體請參考協議,後面具體用到再說
名字 報文流動方向 描述
CONNECT 1 client -> server client 請求鏈接 server
CONNACK 2 server -> client 鏈接報文確認
PINGREQ 12 client -> server 心跳請求
PINGRESP 13 server -> client 心跳響應
DISCONNECT 14 client -> server 客戶端斷開鏈接

(2)標識符

控制報文 固定報文標誌 Bit 3 Bit 2 Bit 1 Bit 0
CONNECT Reserved 0 0 0 0
CONNACK Reserved 0 0 0 0
PINGREQ Reserved 0 0 0 0
PINGRESP Reserved 0 0 0 0
DISCONNECT Reserved 0 0 0 0

(3)剩餘長度

  • 表示當前報文剩餘部分的字節數,包括可變報頭和負載的數據。
  • 它採用了可變長度的編碼方法。
  • 容許最大長度256M
字節數 最小值 最大值
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)

2.3 可變報頭

Bit 7 6 5 4 3 2 1 0
byte 1 報文標識符 MSB
byte 2 報文標識符 LSB
控制報文 報文標識符字段
CONNECT 不須要
CONNACK 不須要
PINGREQ 不須要
PINGRESP 不須要
DISCONNECT 不須要

2.4 有效載荷

控制報文 有效載荷
CONNECT 須要
CONNACK 不須要
PINGREQ 不須要
PINGRESP 不須要
DISCONNECT 不須要

3 MQTT控制報文示例

3.1 CONNECT——鏈接服務器

(1)WireShark抓包獲取報文

MQ Telementry Transport Protocol, Connect Command 
    # 固定報頭(2~5個字節)
    Header Flags: 0x10 (Connect Command) # 固定報頭,1個字節
        0001 .... = Message Type: Connect Command(1) # 報文類型: CONNECT
        .... 0000 = Reserved: 0 # 保留
    Msg Len: 40 # 剩餘長度,0x28,1個字節
   
    # 可變報頭,本例10個字節
    Protocol Name Length: 4 # 協議長度,0x0004,2個字節
    Protocol Name: MQTT # 協議名,MQTT(ASCII:0x4d515454),4個字節
    Version: MQTT v3.1.1 (4) # 協議版本,0x04 1個字節
    Connect Flags: 0xC2 # 鏈接標誌,1個字節,每一位表明不一樣的內容
        1... .... = User Name Flag: Set # 用戶名
        .1.. .... = Password Flag: Set # 密碼
        ..0. .... = Will Retain: Not Set # 遺囑保留
        ...0 0... = Qos Level: At most once deliver (Fire and Forget) (0) # Qos
        .... .0.. = Will Flag: Not Set # 遺囑
        .... ..1. = Clean Session Flag: Set # 清除會話
        .... ...0 = (Reserverd): Not Set # 固定爲0
    Keep Alive: 60 # 保持鏈接,2個字節,0x003C
    
    # 有效載荷,本例30個字節
    Client ID Length: 14,# 2個字節,0x000e
    Client ID: MQTT_FX_client # 14個字節
    User Name Length: 5 # 2個字節,0x0005
    User Name: hello # 5個字節
    Password Length: 5 # 2個字節,0x0005
    Password: world # 5個字節

10 28 00 04 4d 51 54 54 04 c2 00 3c 00 0e 4d 51   .(..MQTT...<..MQ
54 54 5f 46 58 5f 43 6c 69 65 6e 74 00 05 68 65   TT_FX_Client..he
6c 6c 6f 00 05 77 6f 72 6c 64                     llo..world

(2)鏈接標誌

  • 保留(第0位):固定爲0html

  • 清理會話(第1位)設置爲1,表明服務器不須要保存會話狀態,即丟棄會話並開始一個新的會話;若是爲0,須要根據保存的會話狀態恢復當前會話。
    • 客戶端會話狀態:
      • 發送給Sever,但沒有完成確認的Qos1和Qos2的消息
      • 已經從接收,但沒有完成確認的Qos2的消息
    • 服務器會話狀態:
      • 會話是否存在
      • 客戶端的訂閱消息
      • 發送給Client,但沒有完成確認的Qos1和Qos2消息
      • 即將傳輸給Client的Qos1和Qos2消息
      • 從Client接收,但沒有完成確認的Qos2消息
      • 可選,準備發送給Client的Qos0消息
  • 遺囑標誌(第2位):設置爲1時,CONNECT報文的有效在載荷中包含Will Topic和Will Message字段,若是鏈接請求成功,遺囑(Will Message)消息必須被存儲在服務端。以後網絡鏈接關閉時,服務端必須發佈這個遺囑消息,除非服務端收到DISCONNECT報文時刪除了該遺囑消息。下面狀況將發生發佈遺囑消息:
    • Server檢測到一個I/O錯誤或者網絡故障
    • Client在Keep Alive時間內未能通訊(既沒有發送PING)
    • Client沒有先DISCONNECT報文就直接關閉了網絡鏈接
    • 協議錯誤Server關閉了網絡鏈接
  • 遺囑Qos(第3 4位):用於指定發佈遺囑消息時的服務質量等級
    • 遺囑標誌爲0,遺囑Qos也必須爲0。
    • 遺囑標誌爲1,遺囑Qos能夠爲任一服務質量等級。
  • 遺囑保留(第5位):遺囑消息發佈時是否須要保留。
  • 用戶名與密碼標誌(第6 7位)若是爲1,表明有效載荷中帶有用戶名和密碼,服務器能夠獲取並進行驗證shell

(3)保持鏈接時間

  • 2個字節表示,以秒爲單位,最大值爲18小時12分15秒
  • 斷開狀況:
    • Client發送PINGREQ,在合理時間內沒有回來則關閉到Server的網絡鏈接
    • Server在1.5 * 保持鏈接時間 內沒有收到Client的任意控制報文,它將斷開Client的網絡鏈接
  • 設置爲0,表明Server須要由於Client的不活躍而斷開鏈接,可是Server仍然能夠在須要的時候關閉鏈接。

(4)有效載荷

  • 客戶端標識符(Must):長度 + 標識符(大小寫英文或數字),有效載荷的第一個字段,客戶端能夠提供一個零字節的ClientId,可是Clean Seesion必需爲1.
  • 遺囑主體(Option):Will Topic
  • 遺囑消息(Option):Will Message
  • 用戶名(Option):Username
  • 密碼(Option)Password

(5)注意

MQTT Server容許Client發送完CONNECT就發送訂閱或者發佈消息,不過若是驗證不經過,Server將關閉鏈接拒收後面的消息。服務器

3.2 CONNACK——確認鏈接請求

(1)WireShark抓包獲取報文

MQ Telementry Transport Protocol, Connect Command 
    # 固定報頭(2~5個字節)
    Header Flags: 0x20 (Connect Ack) # 固定報頭,1個字節
        0010 .... = Message Type: Connect Ack (2) # 報文類型: CONNACK
        .... 0000 = Reserved: 0 # 保留
    Msg Len: 2 # 剩餘長度,0x02,1個字節
    
    # 可變報頭
    Acknowledge Flags: 0x00 # 鏈接確認標誌
        0000 000. = Reserved: Not Set # 固定爲0
        .... ...0 = Session Present: Not Set # 當前會話標誌
    Return Code: Connection Accepted (0) # 鏈接返回碼

(2)當前會話標誌

  • 若是Server收到一個CleanSession爲1的鏈接,CONNACK報文中的返回碼設置爲0以外,還須要將CONNACK報文中的當前會話標誌設置爲0
  • 若是Server收到一個CleanSeesion爲0的鏈接,當前會話標誌的值取決於Server是否保存了ClientId對應客戶端的會話狀態。若是保存了,當前會話標誌設置爲1,不然爲0。

(3)鏈接返回碼

返回碼響應 描述
0 0x00 鏈接已接收
1 0x01 不支持的協議版本
2 0x02 不合格的客戶端標識符(UTF-8編碼)
3 0x03 MQTT服務端不可用(TCP已鏈接)
4 0x04 無效的用戶名或密碼
5 0x05 未受權此客戶端
6-255 保留

3.3 PINGREQ——心跳請求

(1)WireShark抓包獲取報文

Header Flags: 0xC0 (Ping Request)  # 固定報頭
    1100 .... = Message Type: Ping Request (12)
    .... 0000 = Reserved: 0
Msg Len: 0

(2)做用

  • 在沒有任何其餘控制報文發送給Server時,Client告知Server還活着
  • 請求Server發送響應確認Server是否活着
  • 使用網絡以肯定網絡鏈接沒有斷開

3.4 PINGRESP——心跳響應

(1)WireShark抓包獲取報文

Header Flags: 0xD0 (Ping Response)  # 固定報頭
    1101 .... = Message Type: Ping Response(13)
    .... 0000 = Reserved: 0
Msg Len: 0

(2)做用

  • 告知Client,Server活着

3.5 DISCONNECT——斷開鏈接

(1)WireShark抓包獲取報文

Header Flags: 0xe0 (Disconnect)  # 固定報頭
    1110 .... = Message Type: Disconnect (14)
    .... 0000 = Reserved: 0
Msg Len: 0

(2)做用

  • 客戶端正常斷開鏈接

(3)響應

  • Client發送DISCONNECT報文後
    • 必需關閉網絡鏈接
    • 不能經過該鏈接繼續發送任何控制報文
  • Server收到DISCONNECT報文後
    • 必須丟棄任何與當前鏈接關聯的未發佈的遺囑消息
    • 應該關閉網絡鏈接,若是客戶端尚未這麼作
相關文章
相關標籤/搜索