前言:
上一篇提到用來發佈訊息的PUBLISH Message,接著就來談談訂閱訊息用的SUBSCRIBE Message。
SUBSCRIBE Message
SUBSCRIBE Message允許client對Server上一或多個感興趣的主題(Topic)進行訂閱。當有訊息對主題發佈時,server會將訊息當作PUBLISH Message送給訂閱的client。SUBSCRIBE Message也定義了QoS level,表示它期望以何種QoS level來接收訊息。
Fixed Header:
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
byte 1 | Message Type(8) | DUP flag | QoS level | RETAIN | ||||
1 | 0 | 0 | 0 | 0 | 0 | 1 | x | |
byte 2 | Remaining Length |
上面為SUBSCRIBE Message裡面的fixed header,以下依依介紹它們的作用。
Message Type:每種類型的Message都要用到,要根據想用的訊息類型填上相對應的值,值可以參考先前貼的文章MQTT(二)Message Type and Flows。這邊由於是SUBSCRIBE Message的關係,因此會填上1000。
DUP flag:標記此訊息為重複(duplicate)的訊息,會用在PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE上。當client或是server要重新傳送上述訊息時,則要將此flag設為1。此flag會適用於QoS大於0的訊息。
此flag 只能當成一種提示,表示此則訊息可能在之前有收過了,不應該拿它來當成訊息重複的檢查flag。
QoS level:SUBSCRIBE Message使用QoS level 1來回應(acknowledge)不同的訂閱主題請求。
RETAIN:沒有使用到。
Remaining Length:此欄位記錄當前的Message,它的Variable header和Payload總共的長度為何,此欄位不一定就是1 byte,它是可變得,最多到4 byte。
接著讓我們繼續往下看,再來是第二個Herader,也就是Variable Header。
Variable Header:
由於SUBSCRIBE Message QoS level為1,因此其variable header會包含Message ID,用來確保訊息能夠正確傳送。
下面為SUBSCRIBE Message,variable header欄位範例:
Field | Value |
---|---|
Message ID | 10 |
Payload:
SUBSCRIBE Message的payload會包含一個主題名稱列表,代表該Client想要訂閱的主題,列表內的每個主題都會包括一個期望接收訊息時的QoS level,可以參考MQTT(二)Message Type and Flows:Subscribe Flow來了解QoS level與其影響為何。
主題的名稱可以使用萬用字元(wildcard characters),關於萬用字元稍後會進行說明,以下為SUBSCRIBE Message的payload範例:
Topic name | "a/b" |
Requested QoS | 1 |
Topic name | "c/d" |
Requested QoS | 2 |
上述範例代表該Client想要訂閱兩個主題"a/b"、"c/d",其中主題"a/b"期望用QoS level 1來接收訊息,主題"c/d"期望用QoS level 2來接收訊息。
Response:
當Server接收到從Cleint發送過來的SUBSCRIBE Message,則回應一個SUBACK Message給client。
Server有基於Client已經訂閱的關係,因此可能會開始傳送PUBLISH Message給Client,即使Client還沒收到SUBACK Message。
Server有可能會降低cleint請求的QoS level。這會發生在Server沒辦法提供高level的QoS時。舉例來說,如果Server沒有提供一個可靠的訊息持久機制(persistence mechanism),則它可能只提供QoS level 0給訂閱者。Server提供的QoS level會在SUBACK Message的payload內,依照主題的訂閱順序回應給訂閱者。以下為範例:
Granted QoS | 0 |
Granted QoS | 2 |
主題萬用字元(Topic WildCard Characters):
在訂閱的時候可以使用特出字元,允許你一次訂閱多個主題,此字元稱為萬用字元。
主題層級分隔符號(Topic level separator)被用來對主題做結構化。單一層級的萬用字元和多層級的萬用字元可以被用在訂閱上面,但是不能被用在發佈(publish)訊息上面,也就是說在發佈訊息時,主題要明確定義,不能用萬用字元來同時對多個主題做訊息發佈。
Topic level separator(主題層級分隔符號):
斜線符號(/)用來切割topic tree的每個層級,提供一個有層次的主題空間。使用主題層級分割符號來切割主題,在遇到用萬用字元訂閱該主題時是很有用的,下面接著介紹兩個萬用字元。
Multi-level wildcard(多層級萬用字元):
井字號(#)用來匹配任何層級的主題。舉例來說,如果你用此萬用字元訂閱了 finance/stock/ibm/#,則你將會收到來自於下列主題的訊息:
- finance/stock/ibm
- finance/stock/ibm/closingprice
- finance/stock/ibm/currentprice
多層級萬用字元可以表示零到多個層級,因此 finance/# 可以匹配到 finance 。
多層級萬用字元在以下狀況是有效的,如 # 或是 finance/# ,而以下狀況下是無效的,如 finance# 和 finance/#/closingprice 。
Single-level wildcard(單一層級萬用字元):
加字號(+)用來匹配單一層級的主題。舉例來說 finance/stock/+ 會匹配 /finance/stock/ibm 和 /finance/stock/xyz ,但是不會匹配到 finance/stock/ibm/closingprice 。也由於它只會匹配到一個層級,因此 finance/+ 不會匹配到 finance 。
單一層級萬用字元可以使用在任何層級的主題樹,也可以和多層級萬用字元結合使用。
單一層級萬用字元在以下狀況是有效的,如 + 和 finance/+ 以及 finance/+/ibm 。而以下狀況是無效的,如 finance+ 。
小結
本篇介紹了MQTT的SUBSCRIBE Message,此訊息用於訂閱主題上,而每個想訂閱的主題需要設定期望的QoS level,藉此來表達client對該主題的訊息品質需求。
另外也介紹了主題萬用字元,讓client在訂閱主題時,可以透過萬用字元同時對多個主題進行訂閱。