前言
這次要講到客戶(hù)端/服務(wù)器的發(fā)布消息行為,與PUBLISH相關(guān)的消息類(lèi)型,會(huì)在這里看到。
PUBLISH
客戶(hù)端發(fā)布消息經(jīng)由服務(wù)器分發(fā)到所有對(duì)應(yīng)的訂閱者那里。一個(gè)訂閱者可以訂閱若干個(gè)主題(Topic name),但一個(gè)PUBLISH消息只能擁有一個(gè)主題。
消息架構(gòu)一覽:
| 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,二進(jìn)制對(duì)象形式。二進(jìn)制具體包含的內(nèi)容和格式,可有應(yīng)用程序自身定義。若消息體為空(0長(zhǎng)度)也是可能的。 |
固定頭部
DUP flag,設(shè)為0,表示當(dāng)前為第一次發(fā)送。
RETAIN flag,只有在PUBLISH消息中才有效。
- 1:表示發(fā)送的消息需要一直持久保存,不但要發(fā)送給當(dāng)前的訂閱者,并且以后新來(lái)的訂閱了此Topic name的訂閱者會(huì)馬上得到推送。
備注:新來(lái)乍到的訂閱者,只會(huì)取出最新的一個(gè)RETAIN flag = 1的消息推送,不是所有。
- 0:僅僅為當(dāng)前訂閱者推送此消息。
可變頭部
Topic name,UTF-8編碼字符串形式,不支持通配符!
消息體
一般作為UTF-8編碼寫(xiě)入接口,但不排除自定義的消息格式。
空的消息體(zero-length)的PUBLISH消息也可以是合法的。
當(dāng)服務(wù)器接收到空消息體(zero-length payload)、retain = 1、具有topic name的一個(gè)PUBLISH特殊消息,表示同時(shí)滿(mǎn)足retain = 1、相同topic name的這兩個(gè)特征的被持久化PUBLISH消息,可被刪除。
Response/響應(yīng)
固定頭部QoS level決定了消息中間件針對(duì)發(fā)布者具體需要響應(yīng)的內(nèi)容:
QoS Level |
Expected response |
QoS 0 |
None |
QoS 1 |
PUBACK |
QoS 2 |
PUBREC |
備注:僅僅針對(duì)發(fā)布PUBLISH消息的發(fā)布者。
Actions:
無(wú)論是訂閱者還是服務(wù)器接收到PUBLISH消息之后,需要根據(jù)QoS level執(zhí)行不同動(dòng)作。
QoS Level |
Expected Action |
QoS 0 |
發(fā)送到所有感興趣者 |
QoS 1 |
持久化記錄下來(lái),發(fā)送到所有感興趣的參與者,返回一個(gè)PUBACK消息給發(fā)送者 |
QoS 2 |
持久化記錄下來(lái),暫時(shí)不發(fā)送所有感興趣的參與者,返回一個(gè)PUBREC消息給發(fā)送者 |
如果服務(wù)器收到PUBLISH消息,參與者指的是訂閱者。如果訂閱者收到PUBLISH消息,參與者就是服務(wù)器。
需要注意:
- 發(fā)布者發(fā)布的PUBLISH消息發(fā)送到服務(wù)器,在payload/消息體處可能夾帶有私貨,可能含有自定義的數(shù)據(jù) 格式
- 若兼容MQTT客戶(hù)端,經(jīng)由服務(wù)器分發(fā)到所有對(duì)應(yīng)訂閱者處只能是規(guī)規(guī)矩矩的PUBLISH消息,并且固定頭部的RETAIN標(biāo)志不能被設(shè)置成有效值1
授權(quán)
未經(jīng)授權(quán)的發(fā)布者提交的PUBLISH消息,服務(wù)器會(huì)忽略掉,客戶(hù)端不會(huì)被通知。
PUBACK
作為訂閱者/服務(wù)器接收(QoS level = 1)PUBLISH消息之后對(duì)發(fā)送者的響應(yīng),整個(gè)消息不復(fù)雜。
| 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 |
雖沒(méi)有消息體,但可變頭部附加一個(gè)16位的無(wú)符號(hào)short類(lèi)型。
PUBREC
字面意思為Assured publish received,作為訂閱者/服務(wù)器對(duì)QoS level = 2的發(fā)布PUBLISH消息的發(fā)送方的響應(yīng),確認(rèn)已經(jīng)收到,為QoS level = 2消息流的第二個(gè)消息。
和PUBACK相比,除了消息類(lèi)型不同外,其它都是一樣。
| 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 |
無(wú)論是訂閱者還是服務(wù)器,在消費(fèi)PUBREC消息之后需要發(fā)送一個(gè)PUBREL消息給發(fā)送者(和PUBREC具有同樣的消息ID),確認(rèn)已收到。
PUBREL
Qos level = 2的協(xié)議流的第三個(gè)消息,有PUBLISH消息的發(fā)布者發(fā)送,參與方接收。完整示范如下:
| 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,表示消息第一次被發(fā)送。
毫無(wú)疑問(wèn),剩余長(zhǎng)度為2個(gè)byte長(zhǎng)度。
可變頭部中,消息ID和發(fā)布者接收到的PUBREC所包含的消息ID是一致的。
動(dòng)作:
- 服務(wù)器接收到發(fā)布者(a)的PUBREL消息,此時(shí)服務(wù)器讓發(fā)布者(a)剛才發(fā)布PUBLISH消息可用,發(fā)送此PUBLISH消息給所有訂閱此主題的訂閱者,然后發(fā)送PUBCOMP消息給發(fā)布者(a)
-
可變頭部包含消息ID和服務(wù)器接收的PUBREL消息ID是一致的。
一個(gè)訂閱者接收到PUBREL消息,訂閱者使PUBLISH消息可用,然后反饋一個(gè)PUBCOMP消息給服務(wù)器
PUBCOMP
作為QoS level = 2消息流第四個(gè),也是最后一個(gè)消息,由收到PUBREL的一方向另一方做出的響應(yīng)消息。
完整的消息一覽,和PUBREL一致,除了消息類(lèi)型。
| 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 |
當(dāng)客戶(hù)端接收一個(gè)PUBCOMP消息時(shí),客戶(hù)端摒棄原來(lái)的消息,因?yàn)樗呀?jīng)成功發(fā)送消息到服務(wù)器。
小結(jié)
消息的發(fā)布和確認(rèn)等一些流程,主要是跟消息發(fā)布者所設(shè)定的QoS level有關(guān);稍加整理,繪制了下面一張圖,理解起來(lái)可能會(huì)更清晰些:

上圖針對(duì)的是客戶(hù)端發(fā)布消息到服務(wù)器端的方向。
為了確保消息已經(jīng)成功傳遞過(guò)去,只有收到了確認(rèn),才會(huì)讓人特別放心。
在QoS level = 2時(shí),通信雙方都需要知道各自的確認(rèn)流程以及所處階段等,交互很多,數(shù)據(jù)量大的情況下,可能會(huì)造成數(shù)據(jù)線(xiàn)路傳遞擁塞。服務(wù)器選擇QoS = 0/1,大部分情況都是可以應(yīng)對(duì)的。
比如重要消息,就要確保對(duì)方都要收到,然后彼此確認(rèn),OK,這個(gè)消息是真實(shí)、有效的。
無(wú)論Qos level為0、1,還是2,服務(wù)器(具備所有條件都滿(mǎn)足之后)總要把收到的具體內(nèi)容和topic組裝成一個(gè)新的PUBLISH Message(也不一定要重新構(gòu)造,但要求推送的PUBLISH消息,一定要具有明確的主題和內(nèi)容,RETAIN標(biāo)志不能設(shè)置為1)推送到所有感興趣的訂閱者。
嗯,消息的發(fā)布來(lái)源別忘記還有可能來(lái)自CONNECT消息中的Will Topic和Will Message,若是設(shè)置了Will flag標(biāo)記的話(huà)。