1. 程式人生 > >MQTT協議探究(三)

MQTT協議探究(三)

保存 用法 del 使用 第一次 sha tor 交付 標識符

1 回顧與本次目標

1.1 回顧

  • 主題通配符
  • 主題語義和用法
  • WireShark進行抓包分析了報文
  • 報文分析:
    • SUBSCRIBE——訂閱主題
    • SUBACK——訂閱確認
    • UNNSUBSCRIBE——取消訂閱
    • UNSUBACK——取消訂閱確認
    • PUBLISH——發布消息(Qos0,服務質量等級下一節再說吧)

1.2 本節目標

  • 服務質量等級
  • PUBLISH——發布消息(Qos1 Qos2)
  • PUBACK——發布確認
  • PUBREC——發布收到
  • PUBREL——發布釋放
  • PUBCOMP——發布完成

2 MQTT控制報文格式(補充)

2.1 控制報文的類型

名字 報文流動方向 描述
PUBLISH 3 雙向 發布消息
PUBACK 4 雙向 QoS 1消息發布收到確認
PUBREC 5 雙向 QoS 2發布收到(保證交付第一步)
PUBREL 6 雙向 QoS 2發布釋放(保證交付第二步)
PUBCOMP 7 雙向 QoS 2消息發布完成(保證交互第三步)

2.2 標識符

控制報文 固定報文標誌 Bit 3 Bit 2 Bit 1 Bit 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
  • DUP = 控制報文的重復分發標誌
  • Qos = PUBLISH報文的服務質量等級
  • RETAIN = PUBLISH報文是否保留標誌

2.3 報文標識符

  • Client每次發送一個新的報文時都必須分配一個未使用的報文標識符。
  • Client如果進行重發報文必須使用相同的標識符。
  • 當Client處理完這個報文對應的確認後,這個報文標識符就釋放可重用。
    • QoS 1的PUBLISH對應的是PUBACK
    • QoS 2的PUBLISH對應的是PUBCOMP
控制報文 報文標識符字段
PUBLISH 需要(如果QoS > 0,Qos=0時不能帶)
PUBACK 需要
PUBREC 需要
PUBREL 需要
PUBCOMP 需要

2.4 有效載荷

控制報文 有效載荷
PUBLISH 可選(允許發空負載)
PUBACK 不需要
PUBREC 不需要
PUBREL 不需要
PUBCOMP 不需要

3 服務質量等級和協議流程

3.1 概述

  • 分發協議是對稱的,客戶端和服務端既可以是發送者也可以是接收者。
  • 分發協議關註的是從單個發送者單個接收者的應用消息。
  • 服務端分發應用消息給多個客戶端時,每個客戶端獨立處理。
  • 分發給客戶端的出站應用消息和入站應用消息的QoS等級可能是不同的。

3.2 QoS 0:最多分發一次

  • 接收者不會發送響應(無需確認送達),發送者也不會重試(DUP=0)
  • 發送者必須發送QoS=0,DUP=0的PUBLISH報文
  • 協議流程:
發送者 方向 接收者
PUBLISH報文 Qos=0 DUP=0
------------------->
分發應用消息給適當的後續接收者(們)

3.3 QoS 1: 至少分發一次

  • QoS 1的PUBLISH報文的可變報頭中包含一個報文標識符,需要PUBACK報文(帶上報文標識符)確認。
  • 發送者
    • 新消息都必須分配一個未使用的報文標識符(收到PUBACK時,該報文標識符可以重用)。
    • 發送的PUBLISH報文必須包含報文標識符且QoS=1,DUP=0(不重發)。
    • 必須將這個PUBLISH報文看作是未確認的 ,直到從接收者那收到對應的PUBACK報文。
  • 接收者
    • 響應的PUBACK報文必須包含一個報文標識符 ,這個標識符來自接收到的、已經接受所有權的PUBLISH報文。
    • 發送了PUBACK報文之後,接收者必須將任何包含相同報文標識符的入站PUBLISH報文當作一個新的消息,並忽略它的DUP標誌的值。
  • 協議流程:
發送者 方向 接收者
存儲消息
PUBLISH報文 QoS=1, DUP=0 報文標識符 ------------------->
開始應用消息的後續分發
<------------------- PUBACK報文,帶報文標識符
丟棄消息

3.4 QoS 2: 僅分發一次

  • 消息丟失和重復都是不可接受的
  • 消息可變報頭中有報文標識符
  • 發送者
    • 新消息都必須分配一個未使用的報文標識符(收到PUBCOMP時,該報文標識符可以重用)。
    • PUBLISH報文必須包含報文標識符且報文的QoS=2,,DUP=0。
    • 必須將這個PUBLISH報文看作是未確認的 ,直到從接收者那收到對應的PUBREC報文。
    • 收到PUBREC報文後必須發送一個PUBREL報文(報文標識符)。
    • 必須將這個PUBREL報文看作是 未確認的 ,直到從接收者那收到對應的PUBCOMP報文。
    • 一旦發送了對應的PUBREL報文就不能重發這個PUBLISH報文。
  • 接收者
    • 響應的PUBREC PUBREL PUBCOMP報文必須包含相同的報文標識符
  • 協議流程圖:Client -> Server
發送者 方向 接收者
存儲消息
發送PUBLISH報文,Qos2,DUP=0,帶報文標識符
->
方法A:存儲消息
方法B:存儲報文標識符,開始向前分發這個應用消息
發送PUBREC報文,帶報文標識符
<-
丟棄消息,存儲PUBREC中的報文標識符
發送PUBREL報文,帶報文標識符
->
方法A:開始向前分發應用消息並丟棄
方法B:丟棄報文標識符
發送PUBCOMP報文,帶報文標識符
<-
丟棄已保存的報文標識符
  • 協議流程圖:Server -> Subscriber(來自:http://www.blogjava.net/yongboy/archive/2014/02/15/409893.html)
Server Message and direction Subscriber
QoS = 2
DUP = 0
Message ID = x
PUBLISH ------> Action: Store message
PUBREC <------- Message ID = x
Message ID = x PUBREL -------> Actions:Make message available
PUBCOMP <----- Message ID = x

4 MQTT控制報文示例

4.1 PUBLISH – 發布消息

(1)WireShark抓包獲取報文

# Qos1
MQ Telemetry Transport Protocol, Publish Message
    Header Flags: 0x32 (Publish Message)
        0011 .... = Message Type: Publish Message (3)
        .... 0... = DUP Flag: Not set
        .... .01. = QoS Level: At least once delivery (Acknowledged deliver) (1)
        .... ...0 = Retain: Not set
    Msg Len: 18
    Topic Length: 4 # 0x0004
    Topic: TEST 
    Message Identifier: 1 # 0x0001,報文標識符
    Message: HelloWorld # 18 - 2 - 4 - 2 = 10個字節

# Qos2
MQ Telemetry Transport Protocol, Publish Message
    Header Flags: 0x34 (Publish Message)
        0011 .... = Message Type: Publish Message (3)
        .... 0... = DUP Flag: Not set
        .... .10. = QoS Level: Exactly once delivery (Assured Delivery) (2)
        .... ...0 = Retain: Not set
    Msg Len: 18
    Topic Length: 4
    Topic: TEST
    Message Identifier: 2

(2)固定報頭

  • 重發標誌:DUP為0,代表Client第一次發這個報文;DUP為1,代表Client重發已發的報文。對於Qos為0時,DUP必須為0。

  • 服務質量等級

Qos Bit2 Bit1 描述
0 0 0 最大分發一次
1 0 1 至少一次
2 1 0 只分發一次
- 1 1 保留位

(3)響應

服務質量等級 預期響應
Qos0 無響應
Qos1 PUBACK報文
Qos2 PUBREC報文

4.2 PUBACK –發布確認

(1)WireShark抓包獲取報文

MQ Telemetry Transport Protocol, Publish Ack
    Header Flags: 0x40 (Publish Ack)
        0100 .... = Message Type: Publish Ack (4)
        .... 0000 = Reserved: 0
    Msg Len: 2
    Message Identifier: 1 # 報文標識符

(2)概述

  • PUBACK報文只需要表明接收者收到了某條PUBLISH報文即可。
  • Client設置CleanSession=0重連時,Client和Server必須使用原始的報文標識符重發未確認的PUBLISH報文。
  • 因為存在重發和報文標誌符的復用(Receiver返回PUBACK後,即使有相同的報文標識符,也認為是新的PUBLISH報文),所以可能存在轉發超過一次(Qos1只保證至少1次)的情況。

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

(1)WireShark抓包獲取報文

MQ Telemetry Transport Protocol, Publish Received
    Header Flags: 0x50 (Publish Received)
        0101 .... = Message Type: Publish Received (5)
        .... 0000 = Reserved: 0
    Msg Len: 2
    Message Identifier: 2

(2)概述

  • 3.4節提到Reciver收到Qos2的PUBLISH報文後,可以有兩種處理方式
    • A:存儲消息
    • B:存儲報文標識符(不再分發相同報文標識符的PUBLISH報文),開始分發這個應用消息
  • PUBREC報文是為了告訴Sender收到了消息
  • 其實PUBREC與PUBACK作用相同,表示Receiver已收到消息,所以可以把存儲在Sender的消息刪除(消息的所有權轉讓)

4.4 PUBREL – 發布釋放

(1)WireShark抓包獲取報文

MQ Telemetry Transport Protocol, Publish Release
    Header Flags: 0x62 (Publish Release)
        0110 .... = Message Type: Publish Release (6)
        .... 0010 = Reserved: 2
    Msg Len: 2
    Message Identifier: 2

(2)概述

  • Sender收到PUBREC之前,Sender仍然可能在發送相同報文標識符的PUBLISH報文,所以收到PUBREC之後需要把報文標識符記錄下來(不再發送該報文標識符的PUBLISH報文)。
  • Sender發送PUBREL報文是為了通知Receiver,可以開始接收相同報文標識符的PUBLISH報文了(報文標識符的復用)。
  • 但Sender在沒有收到響應(PUBCOMP)之前,仍然不會去發送相同報文標識符的PUBLISH報文。

4.5 PUBCOMP – 發布完成

(1)WireShark抓包獲取報文

MQ Telemetry Transport Protocol, Publish Complete
    Header Flags: 0x70 (Publish Complete)
        0111 .... = Message Type: Publish Complete (7)
        .... 0000 = Reserved: 0
    Msg Len: 2
    Message Identifier: 2

(2)概述

  • Receiver收到了PUBREL報文
    • A:開始分發消息並丟棄
    • B:丟棄報文標識符(可以接收相同報文標識符的PUBLISH報文)
  • 發送PUBCOMP告知Sender,可以發送相同報文標識符的PUBLISH報文了。

MQTT協議探究(三)