2014年2月14日

MQTT(四)PUBLISH Message

前言:

上一篇提到建立起連線用的CONNECT Message,接著來談談和發佈訊息有關的Message,PUBLISH Message。

PUBLISH Message

PUBLISH Message是發佈訊息時會用到的訊息類型,它會使用在兩個方向:

  1. client對某個主題(Topic)散佈訊息,此時它會發送PUBLISH Message給Server。
  2. server收到了client發送給某個主題的訊息,server會把這些訊息已PUBLISH Message的方式發送給訂閱此主題的client。

每個PUBLISH Message都會包含一個topic name,代表此訊息要發送給哪個主題。

Fixed Header:

bit 7 6 5 4 3 2 1 0
byte 1 Message Type(3) DUP flag QoS level RETAIN
0 0 1 1 0 0 1 0
byte 2 Remaining Length

上面為PUBLISH Message裡面的fixed header,以下依依介紹它們的作用。

  • Message Type:每種類型的Message都要用到,要根據想用的訊息類型填上相對應的值,值可以參考先前貼的文章MQTT(二)Message Type and Flows。這邊由於是PUBLISH Message的關係,因此會填上0011。

  • DUP flag:標記此訊息為重複(duplicate)的訊息,會用在PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE上。當client或是server要重新傳送上述訊息時,則要將此flag設為1。此flag會適用於QoS大於0的訊息。

    此flag 只能當成一種提示,表示此則訊息可能在之前有收過了,不應該拿它來當成訊息重複的檢查flag。

  • QoS level:設定此訊息的QoS level,只有在PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE才會用到。可以參考MQTT(二)Message Type and Flows:PUBLISH flow來得知比較詳細的資訊。

  • RETAIN:設定訊息是否要保留在server上,此特性只有PUBLISH才會用到。當client發送PUBLISH Message給Server上的某個Topic時,如果將此flag設為1,則Server將此訊息發佈給當前的所以訂閱者後,必須將此訊息保留。

    當有一個新的client對此Topic進行訂閱,則Server必須把最後一則Retain flag設為1的訊息傳送給該client。被設為Retain的訊息必須保留直到Server重啟為止。

    此機制會適用於訊息與訊息之間會有一段時間的場景,也就是說,訊息的發佈(Publish)可能不是那麼的頻繁,如錯誤回報的系統。它可以讓新的訂閱者馬上知道上次的最新狀況為何。

  • Remaining Length:此欄位記錄當前的Message,它的Variable header和Payload總共的長度為何,此欄位不一定就是1 byte,它是可變得,最多到4 byte。

接著讓我們繼續往下看,再來是第二個Herader,也就是Variable Header。

Variable Header:

PUBLISH Message的Variable header會包含以下欄位:

  • Topic name:

    一個UTF的編碼字串,它必須是一個明確的主題定義。不能為萬用字元(wildcard characters),關於萬用字元會在後面的篇幅做介紹。這邊只需知道,當訂閱者用萬用字元訂閱到此主題時,此訂閱者收到的PUBLISH訊息裡面的Topic name欄位會是完整的名稱,而不是用萬用字元匹配到的名稱。

  • Message ID:

    Message ID會使用在QoS level 1或是2的下列訊息上面:PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK。

    Message ID為16bit無符號的整數,代表特定方向訊息唯一的id,每個client都會維護他們自己的Message ID列表。所以有可能會有一種狀況發生,就是某個client在發佈Message ID為1的訊息給server時,同時收到Server發佈過來Message ID為1的訊息。

    Message ID不能為0,它會被視為無效的Message ID。

    下面為PUBLISH Message QoS level為1時,variable header欄位範例:

Field Value
Topic Name: "a/b"
Message ID 10

Payload:

PUBLISH Message的payload會包含要發佈的訊息內容。Payload長度為0的訊息是有效的。

Response:

PUBLISH Message的回應會跟QoS level有關係,下表顯示QoS level與預期的回應:

Qos Level Expected response
Qos 0 None
QoS 1 PUBACK
QoS 2 PUBREC

PUBLISH Message可以是從client發佈給Server,或者是從server發佈給訂閱者。在收到訊息時,根據QoS level會做以下的動作:

  • QoS 0:

    將訊息提供給任何有興趣的訂閱者。

  • QoS 1:

    將訊息記錄到儲存裝置(persistent storage),將它提供給任何有興趣的訂閱者,然後回傳PUBACK給發送端。

  • QoS 2:

    將訊息記錄到儲存裝置,不要馬上將它提供給任何有興趣的訂閱者,先回傳PUBREC給發送端。

可以參考MQTT(二)Message Type and Flows:PUBLISH flow來得知比較詳細的資訊。

小結

本篇介紹了MQTT的PUBLISH Message,PUBLISH Message其實要注意的就是QoS level和Retain這兩個特性,QoS level會影響到訊息的可靠度,而Retain可以讓新的訂閱者在訂閱主題時就能得知此主題最新的狀態。了解這兩個特性會可以幫助整體服務架構的規劃。

另外還需要注意到,一次只能對一個Topic發佈訊息,所以沒辦法做到一次同時對多個Topic發佈訊息。

參考:

MQTT V3.1 Protocol Specification