MQTT協議筆記之發布流程
前言
這次要講到客戶端/服務器的發布消息行為,與PUBLISH相關的消息類型,會在這里看到。
PUBLISH
客戶端發布消息經由服務器分發到所有對應的訂閱者那里。一個訂閱者可以訂閱若干個主題(Topic name),但一個PUBLISH消息只能擁有一個主題。
消息架構一覽:
Description | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
---|---|---|---|---|---|---|---|---|---|---|
Fixed header/固定頭部 | ||||||||||
byte 1 | Message Type(3) | DUP flag | QoS level | RETAIN | ||||||
0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | |||
byte 2 | Remaining Length | |||||||||
Variable header/可變頭部 | ||||||||||
Topic name | ||||||||||
byte 1 | Length MSB (0) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
byte 2 | Length LSB (3) | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | |
byte 3 | 'a' (0x61) | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | |
byte 4 | '/' (0x2F) | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | |
byte 5 | 'b' (0x62) | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | |
Message Identifier | ||||||||||
byte 6 | Message ID MSB (0) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
byte 7 | Message ID LSB (10) | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | |
Playload/消息體 | ||||||||||
BLOB,二進制對象形式。二進制具體包含的內容和格式,可有應用程序自身定義。若消息體為空(0長度)也是可能的。 |
固定頭部
DUP flag,設為0,表示當前為第一次發送。
RETAIN flag,只有在PUBLISH消息中才有效。
- 1:表示發送的消息需要一直持久保存,不但要發送給當前的訂閱者,并且以后新來的訂閱了此Topic name的訂閱者會馬上得到推送。 備注:新來乍到的訂閱者,只會取出最新的一個RETAIN flag = 1的消息推送,不是所有。
- 0:僅僅為當前訂閱者推送此消息。
可變頭部
Topic name,UTF-8編碼字符串形式,不支持通配符!
消息體
一般作為UTF-8編碼寫入接口,但不排除自定義的消息格式。
空的消息體(zero-length)的PUBLISH消息也可以是合法的。
當服務器接收到空消息體(zero-length payload)、retain = 1、具有topic name的一個PUBLISH特殊消息,表示同時滿足retain = 1、相同topic name的這兩個特征的被持久化PUBLISH消息,可被刪除。
Response/響應
固定頭部QoS level決定了消息中間件針對發布者具體需要響應的內容:
QoS Level | Expected response |
QoS 0 | None |
QoS 1 | PUBACK |
QoS 2 | PUBREC |
備注:僅僅針對發布PUBLISH消息的發布者。
Actions:
無論是訂閱者還是服務器接收到PUBLISH消息之后,需要根據QoS level執行不同動作。
QoS Level | Expected Action |
QoS 0 | 發送到所有感興趣者 |
QoS 1 | 持久化記錄下來,發送到所有感興趣的參與者,返回一個PUBACK消息給發送者 |
QoS 2 | 持久化記錄下來,暫時不發送所有感興趣的參與者,返回一個PUBREC消息給發送者 |
如果服務器收到PUBLISH消息,參與者指的是訂閱者。如果訂閱者收到PUBLISH消息,參與者就是服務器。 需要注意:
- 發布者發布的PUBLISH消息發送到服務器,在payload/消息體處可能夾帶有私貨,可能含有自定義的數據 格式
- 若兼容MQTT客戶端,經由服務器分發到所有對應訂閱者處只能是規規矩矩的PUBLISH消息,并且固定頭部的RETAIN標志不能被設置成有效值1
授權
未經授權的發布者提交的PUBLISH消息,服務器會忽略掉,客戶端不會被通知。
PUBACK
作為訂閱者/服務器接收(QoS level = 1)PUBLISH消息之后對發送者的響應,整個消息不復雜。
Description | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
Fixed header/固定頭部 | |||||||||
byte 1 | Message type (4) | DUP flag | QoS flags | RETAIN | |||||
0 | 1 | 0 | 0 | x | x | x | x | ||
byte 2 | Remaining Length (2) | ||||||||
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ||
Variable header/可變頭部 | |||||||||
Message Identifier | |||||||||
byte 1 | Message ID MSB (0) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
byte 2 | Message ID LSB (10) | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
雖沒有消息體,但可變頭部附加一個16位的無符號short類型。
PUBREC
字面意思為Assured publish received,作為訂閱者/服務器對QoS level = 2的發布PUBLISH消息的發送方的響應,確認已經收到,為QoS level = 2消息流的第二個消息。 和PUBACK相比,除了消息類型不同外,其它都是一樣。
Description | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
Fixed header/固定頭部 | |||||||||
byte 1 | Message type (5) | DUP flag | QoS flags | RETAIN | |||||
0 | 1 | 0 | 1 | x | x | x | x | ||
byte 2 | Remaining Length (2) | ||||||||
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ||
Variable header/可變頭部 | |||||||||
Message Identifier | |||||||||
byte 1 | Message ID MSB (0) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
byte 2 | Message ID LSB (10) | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
無論是訂閱者還是服務器,在消費PUBREC消息之后需要發送一個PUBREL消息給發送者(和PUBREC具有同樣的消息ID),確認已收到。
PUBREL
Qos level = 2的協議流的第三個消息,有PUBLISH消息的發布者發送,參與方接收。完整示范如下:
Description | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
Fixed header/固定頭部 | |||||||||
byte 1 | Message type (6) | DUP flag | QoS flags | RETAIN | |||||
0 | 1 | 1 | 0 | 0 | 0 | 1 | x | ||
byte 2 | Remaining Length (2) | ||||||||
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ||
Variable header/可變頭部 | |||||||||
Message Identifier | |||||||||
byte 1 | Message ID MSB (0) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
byte 2 | Message ID LSB (10) | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
QoS level 1,PUBREL消息要求如此。
DUP flag 為0,表示消息第一次被發送。
毫無疑問,剩余長度為2個byte長度。
可變頭部中,消息ID和發布者接收到的PUBREC所包含的消息ID是一致的。
動作:
- 服務器接收到發布者(a)的PUBREL消息,此時服務器讓發布者(a)剛才發布PUBLISH消息可用,發送此PUBLISH消息給所有訂閱此主題的訂閱者,然后發送PUBCOMP消息給發布者(a)
- 可變頭部包含消息ID和服務器接收的PUBREL消息ID是一致的。 一個訂閱者接收到PUBREL消息,訂閱者使PUBLISH消息可用,然后反饋一個PUBCOMP消息給服務器
PUBCOMP
作為QoS level = 2消息流第四個,也是最后一個消息,由收到PUBREL的一方向另一方做出的響應消息。
完整的消息一覽,和PUBREL一致,除了消息類型。
Description | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
---|---|---|---|---|---|---|---|---|---|
Fixed header/固定頭部 | |||||||||
byte 1 | Message type (7) | DUP flag | QoS flags | RETAIN | |||||
0 | 1 | 1 | 1 | x | x | x | x | ||
byte 2 | Remaining Length (2) | ||||||||
0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ||
Variable header/可變頭部 | |||||||||
Message Identifier | |||||||||
byte 1 | Message ID MSB (0) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
byte 2 | Message ID LSB (10) | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
當客戶端接收一個PUBCOMP消息時,客戶端摒棄原來的消息,因為它已經成功發送消息到服務器。
小結
消息的發布和確認等一些流程,主要是跟消息發布者所設定的QoS level有關;稍加整理,繪制了下面一張圖,理解起來可能會更清晰些:
上圖針對的是客戶端發布消息到服務器端的方向。
為了確保消息已經成功傳遞過去,只有收到了確認,才會讓人特別放心。
在QoS level = 2時,通信雙方都需要知道各自的確認流程以及所處階段等,交互很多,數據量大的情況下,可能會造成數據線路傳遞擁塞。服務器選擇QoS = 0/1,大部分情況都是可以應對的。 比如重要消息,就要確保對方都要收到,然后彼此確認,OK,這個消息是真實、有效的。
無論Qos level為0、1,還是2,服務器(具備所有條件都滿足之后)總要把收到的具體內容和topic組裝成一個新的PUBLISH Message(也不一定要重新構造,但要求推送的PUBLISH消息,一定要具有明確的主題和內容,RETAIN標志不能設置為1)推送到所有感興趣的訂閱者。
嗯,消息的發布來源別忘記還有可能來自CONNECT消息中的Will Topic和Will Message,若是設置了Will flag標記的話。
posted on 2014-02-10 23:42 nieyong 閱讀(17358) 評論(5) 編輯 收藏 所屬分類: MQTT