1 回顧與本次目標
1.1 回顧
- MQTT控制報文的基本格式
- WireShark進行抓包分析了報文
- 報文分析:
- CONNECT——鏈接服務器
- CONNACK——確認鏈接請求
- PINGREQ——心跳請求
- PINGRESP——心跳響應
- DISCONNECT——斷開鏈接
1.2 本節目標
- SUBSCRIBE——訂閱主題
- SUBACK——訂閱確認
- UNNSUBSCRIBE——取消訂閱
- UNSUBACK——取消訂閱確認
- PUBLISH——發佈消息(Qos0,服務質量等級下一節再說吧)
2 MQTT控制報文格式(補充)
2.1 控制報文的類型
SUBSCRIBE |
8 |
client -> server |
客戶端訂閱請求 |
SUBACK |
9 |
server -> client |
訂閱請求報文確認 |
PUBLISH |
3 |
雙向 |
發佈消息 |
UNSUBSCRIBE |
10 |
client -> server |
取消訂閱請求 |
UNSUBACK |
11 |
server -> client |
取消訂閱報文確認 |
2.2 標識符
SUBSCRIBE |
Reserved |
0 |
0 |
1 |
0 |
SUBACK |
Reserved |
0 |
0 |
0 |
0 |
PUBLISH |
Used in MQTT 3.1.1 |
DUP |
QoS |
QoS |
RETAIN |
UNSUBSCRIBE |
Reserved |
0 |
0 |
1 |
0 |
UNSUBACK |
Reserved |
0 |
0 |
0 |
0 |
- DUP = 控制報文的重複分發標誌
- Qos = PUBLISH報文的服務質量等級
- RETAIN = PUBLISH報文是否保留標誌
2.3 報文標識符
- 顧名思義就是標識報文的惟一性
- SUBSCRIBE,UNSUBSCRIBE和PUBLISH(QoS大於0)控制報文必須包含一個非零的16位報文標識符(Packet Identifier)。
- Client每次發送一個新的報文時都必須分配一個未使用的報文標識符。
- Client若是進行重發報文必須使用相同的標識符。
- 當Client處理完這個報文對應的確認後,這個報文標識符就釋放可重用。
- QoS 1的PUBLISH對應的是PUBACK
- QoS 2的PUBLISH對應的是PUBCOMP
- SUBSCRIBE對應的分別是SUBACK
- UNSUBSCRIBE對應的時UNSUBACK
SUBSCRIBE |
須要 |
SUBACK |
須要 |
PUBLISH |
須要(若是QoS > 0,Qos=0時不能帶) |
UNSUBSCRIBE |
須要 |
UNSUBACK |
須要 |
2.4 有效載荷
SUBSCRIBE |
須要 |
SUBACK |
須要 |
PUBLISH |
可選(容許發空負載) |
UNSUBSCRIBE |
須要 |
UNSUBACK |
不須要 |
3 MQTT控制報文示例
3.1 SUBSCRIBE——訂閱主題
(1)WireShark抓包獲取報文
MQ Telemetry Transport Protocol, Subscribe Request
# 固定報頭
Header Flags: 0x82 (Subscribe Request)
1000 .... = Message Type: Subscribe Request (8)
.... 0010 = Reserved: 2
Msg Len: 9
# 可變報頭
Message Identifier: 1 # 2個字節,0x0001,報文標識符
# 有效載荷
Topic Length: 4 # 2個字節,0x0004,Topic的長度
Topic: TEST # 2個字節,0x54455354,Topic的值
Requested QoS: At most once delivery (Fire and Forget) (0) # 1個字節 Qos0 0x00
(2)Topic
(3)響應
- Server收到Client發送的一個SUBSCRIBE報文時,必須使用SUBACK報文響應
- SUBACK報文必須和等待確認的SUBSCRIBE報文有相同的報文標識符
- 容許Server在發送SUBACK報文以前就開始發送與訂閱匹配的PUBLISH報文
- 若是Server收到的SUBSCRIBE報文,Topic與現存的Topic相同,則使用新的訂閱(新Qos)替換現存的訂閱。
- Client被受權的Qos爲0,那麼Client發送Qos2將會降級爲0。
3.2 SUBACK – 訂閱確認
(1)WireShark抓包獲取報文
MQ Telemetry Transport Protocol, Subscribe Ack
# 固定報頭
Header Flags: 0x90 (Subscribe Ack)
1001 .... = Message Type: Subscribe Ack (9)
.... 0000 = Reserved: 0
Msg Len: 3
# 可變報頭
Message Identifier: 1 # 2個字節,0x0001,與SUBSCRIBE相同
# 有效載荷
Granted QoS: At most once delivery (Fire and Forget) (0) # 返回碼,最大Qos
(2)返回碼
- 0x00 - 成功,最大Qos0
- 0x01 - 成功,最大Qos1
- 0x02 - 成功,最大Qos2
- 0x80 - 失敗
3.3 PUBLISH – 發佈消息(Qos0)
(1)WireShark抓包獲取報文
MQ Telemetry Transport Protocol, Publish Message
# 固定報頭
Header Flags: 0x30 (Publish Message)
0011 .... = Message Type: Publish Message (3) # 表明發佈消息
.... 0... = DUP Flag: Not set # 重發標誌
.... .00. = QoS Level: At most once delivery (Fire and Forget) (0) # Qos
.... ...0 = Retain: Not set # 保留標誌
Msg Len: 16
# 可變報頭
### 主題名
Topic Length: 4 # 2個字節,0x0004
Topic: TEST # 4個字節
### 報文標識符,當Qos不爲0時,必須帶上。
# 有效載荷
Message: HelloWorld
(2)固定報頭
0 |
0 |
0 |
最大分發一次 |
1 |
0 |
1 |
至少一次 |
2 |
1 |
0 |
只分發一次 |
- |
1 |
1 |
保留位 |
(3)保留標誌(RETAIN)
- Client發送給Server報文的RETAIN爲0,Server不能存儲這個消息,也不能移除或替換任何現存的消息。
- Client發送給Server報文的RETAIN爲1,Server必須存儲該消息和Qos,以便分發給將來的主題名匹配的訂閱者。(若是有新的訂閱,Server存在最近保留的消息,它將發送保留消息給新的Client。而且Server發送的該消息必須將RETAIN設爲0.)
- Server不保留零字節(有效載荷)的保留消息。
- Client發送給Server報文的RETAIN爲1,Qos爲0,Server必須丟棄以前爲那個Topic保留的任何消息,並保留該消息,可是該消息也是能夠被丟棄的。
(4)響應
Qos0 |
無響應 |
Qos1 |
PUBACK報文 |
Qos2 |
PUBREC報文 |
(5)動做
- 客戶端使用帶通配符的主題過濾器請求訂閱時,客戶端的訂閱可能會重複,所以發佈的消息可能會匹配多個過濾器,因此服務端必須將消息分發給全部訂閱匹配的QoS等級最高的客戶端。
3.4 UNSUBSCRIBE –取消訂閱
(1)WireShark抓包獲取報文
MQ Telemetry Transport Protocol, Unsubscribe Request
# 固定報頭
Header Flags: 0xa2 (Unsubscribe Request)
1010 .... = Message Type: Unsubscribe Request (10)
.... 0010 = Reserved: 2
Msg Len: 8
# 可變報頭
Message Identifier: 2 # 報文標識符,0x0002
# 有效載荷
Topic Length: 4
Topic: TEST
(2)響應
- UNSUBSCRIBE報文提供的主題過濾器(不管是否包含通配符)必須與服務端持有的這個客戶端的當前主題過濾器集合逐個字符比較。若是有任何過濾器徹底匹配,那麼它(Server)本身的訂閱將被刪除,不然直接返回SUBACK響應。
- Server刪除了一個訂閱:
- 必須中止分發任何新消息給該Client
- 必須完成分發任何已經開始發往Client發送的QoS 1和QoS 2的消息
- 能夠繼續發送任何現存的準備分發給客戶端的緩存消息
- 即便Server沒有刪除任何訂閱消息,服務器也須要發送一個SUBACK響應。
- 若是服務端收到包含多個主題過濾器的UNSUBSCRIBE報文,它必須如同收到了一系列的多個UNSUBSCRIBE報文同樣處理那個報文,除了將它們的響應合併到一個單獨的UNSUBACK報文外。(這句話有疑惑??)
3.5 UNSUBACK – 取消訂閱確認
(1)WireShark抓包獲取報文
MQ Telemetry Transport Protocol, Unsubscribe Ack
Header Flags: 0xb0 (Unsubscribe Ack)
1011 .... = Message Type: Unsubscribe Ack (11)
.... 0000 = Reserved: 0
Msg Len: 2
Message Identifier: 2
4 訂閱的主題名與主題過濾器
4.1 主題通配符
- 主題分割符號:/
- 主題多層通配符:#,必須在最後面且只有一個
- sport/tennis/#/ranking 無效
- sport/tennis#" 無效
- 主題單層通配符:+,能夠有多個
# demo1:多層通配符
訂閱:"sport/tennis/player1/#"
收到:sport/tennis/player1
sport/tennis/player1/ranking
sport/tennis/player1/score/wimbledon
# demo2: 單層通配符
訂閱:"sport/+"
收到: sport/tennis
收不到: sport
sport/
# demo3:單層通配符
訂閱:"+"
收到: sport
收不到: sport/
# demo4:單層通配符
訂閱:"+/"
收到: sport/
收不到: sport
4.2 以$開頭的主題(非絕對)
- $一般預留給服務器使用(非絕對,具體看服務器的配置)
- $SYS/ 被普遍用做包含服務器特定信息或控制接口的主題的前綴
- 訂閱」#「不會收到」$「開頭的主題消息
- +/monitor/Clients不會收到的客戶端不會收到任何發佈到 「$SYS/monitor/Clients」 的消息
4.3 主題語義和用法
- 只包含斜槓 「/」 的主題名或主題過濾器是合法的
- 主題名和主題過濾器能夠包含空格
- 主題名和主題過濾器是區分大小寫的
- 主題名或主題過濾器以前置或後置斜槓 「/」 區分
- 主題名和主題過濾器不能包含空字符(Unicode U+0000)
- 主題名和主題過濾器不能只有空格符
- 主題名和主題過濾器是UTF-8編碼字符串,它們不能超過65535字節