MQTT協議探究(三)
阿新 • • 發佈:2018-11-13
保存 用法 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協議探究(三)