初識MQTT
到了物聯網時代,由於智能硬體的差異,相比互連網終端,硬體設定要低的多,而且智慧型裝置的環境也想多複雜,物聯網中的資料轉送會面臨很多問題,比如在網路不穩定的情況下,如果保證資料的傳輸沒有問題,如何保證資料不被重複發送,串連斷開後如何進行重連,而HTTP協議由於太重量級了,不是適合物聯網。因此IBM公司為此提出一種輕量級的MQTT協議。
MQTT(Message Queuing Telemetry Transport),是一個物聯網傳輸協議,它被設計用於輕量級的發布/訂閱式訊息傳輸,旨在為低頻寬和不穩定的網路環境中的物聯網裝置提供可靠的網路服務。MQTT是專門針對物聯網開發的輕量級傳輸協議。MQTT協議針對低頻寬網路,低計算能力的裝置,做了特殊的最佳化,使得其能適應各種物聯網應用情境。
如今很多第三方推送平台都採用了MQTT來實現,訊息中介軟體ActiveMQ的訂閱/發布模組也是基於MQTT實現的。 MQTT的實現模型
MQTT訊息代理:即Message Service器,作用是處理客訂閱/發布的請求
MQTT用戶端:需要注意的是,在MQTT的業務模型當中,訊息發行者和訊息訂閱者都屬於客戶,也就是說一個客戶既發行就緒訊息也可以訂閱某個訊息
主題名稱(Topic name)用來標識發行訊息的資訊的渠道。訂閱者用它來確定接收到所關心的資訊。它是一個分層的結構,用斜線“/”作為分隔字元。有兩種萬用字元可以在主題發布、訂閱時使用:“#”和“+”。前者可以通配多層結構,而後者只能通配一層結構。例如一個topic : “a/b/c”,則“a/+/c”和“a/#”都可以和它相等。發布不支援模糊比對,必須是確定的主題。 服務品質
在MQTT中用QoS表示服務品質,有以下三種取值:
1)QoS=0,至多一次,可能會出現丟包的現象。使用在對即時性要求不高的情況。這一層級可應用於如下情景,如環境感應器資料,丟失一次讀記錄無所謂,因為很快下一次讀記錄就會產生。
2)QoS=1,至少一次,保證包會到達目的地,但是可能出現重包。
3)QoS=2,正好一次,保證包會到達目的地,且不會出現重包的現象。這一層級可用於如計費系統等情境,在計費系統中,訊息丟失或重複可能會導致建置錯誤的費用。 報文格式
每個MQTT命令訊息的訊息頭部都包含了一個固定頭部。其中一些類型的訊息可能還需要一個可變頭部和一個有效載荷(可理解為訊息體)。MQTT報文的固定頭部只有2個位元組,這也是相比其他協議更加輕量的原因。 BYTE1
包含訊息類型和標誌(包括DUP,QoS level和RETAIN)欄位,QoS我們在上文中已經提過。現在我們看一下另外幾個欄位。
訊息類型(Message Type) 標識 計數 描述 Reserved 0 保留 Connect 1 用戶端到服務端的串連請求 ConnACK 2 服務端對串連請求的響應 Publish 3 發布訊息 puback 4 對發布訊息的回應 pubRec 5 收到發布訊息(保證傳輸part1) pubRel 6 釋放發布訊息(保證傳輸part2) pubComp 7 完成發布訊息(保證傳輸part3) subscribe 8 客訂閱請求 subBack 9 訂閱請求的回應 unsubscribe 10 停止訂閱請求 unsubBack 11 停止訂閱請求響應 pingReq 12 Ping請求(保持串連) pingResp 13 Ping響應 disconnect 14 用戶端正在斷開 reserved 15 保留
DUP
當用戶端或伺服器試圖重發 PUBLISH、PUBREL、SUBSRIBE、UNSUBSCRIBE 訊息時,該標誌位要被置位(即設為1)。這適用於訊息的QoS標誌值大於0的情況,此時訊息確認是必需的。當DUP位被置位時,可變頭部將包含一個訊息ID。
訊息的接收者應當將該標誌視為該訊息之前可能已收到的提示訊息,而不該依賴於它進行訊息重複資料偵測。
RETAIN
該標誌位只用於 PUBLISH 訊息。當一個用戶端發送一條 PUBLISH 訊息給伺服器,假設該訊息所屬的主題(topic)為topicA,如果該標誌位被置位(1),伺服器在將該條訊息發布給當前的所有topicA的訂閱者之後,還應當保持這條訊息。
當topicA出現了一個新的訂閱者,則topicA的最後一條保持訊息應當發給該訂閱者。當然,如果不存在保持訊息,則什麼也不用發。
當訊息發行者以基於 “report by exception” 的方式發送訊息時,這個功能就特別有用,因為這種情況下,訊息發送間隔往往較長。這個功能使得新的訂閱者可以立刻收到之前保持的或上一個確定有效訊息。
當伺服器收到某個主題的 PUBLISH 訊息時,對於之前已經訂閱該主題的用戶端,伺服器將給這些用戶端發送這一 PUBLISH 訊息,發送前,伺服器會將該訊息的 RETAIN 標誌置為0(即不置位),不管伺服器之前收到該 PUBLISH 訊息時其 RETAIN 標誌是否被置位。這樣做可以使得區分它接收到的 PUBLISH 訊息是伺服器之前保持的(RETAIN標誌置位)還是即時收到的(RETAIN標誌不置位)。
保持訊息應當在重啟伺服器後仍能保留。
如果伺服器收到有效載荷長度為0或重複主題的保持訊息,伺服器可以刪除該保持訊息。 BYTE2
該欄位表示當前訊息的剩餘內容的位元組數,包括可變頭部和有效載荷的資料 三類QoS的實現方式
QoS=0時,並且它保證一次資訊儘力交付。一個訊息不會被接收端應答,也不會被寄件者儲存並再發送。這個也被叫做“即發即棄”。並且在TCP協議下也是會有相同的擔保。
QoS=1時,訊息最少發送1次,它保證資訊將會被至少發送一次給接受者。但是訊息也可能被發送兩次甚至更多。寄件者將會儲存發送的資訊直到寄件者收到一次來自接收者的PUBACK格式的應答。PUBLISH 與PUBACK的關聯是通過比較資料包中的packet identifier完成的。如果在特定的時間內(timeout)發送端沒有收到PUBACK應答,那麼寄件者會重新發送PUBLISH訊息。如果接受者接收到QoS為1 的訊息,它會立即處理這裡訊息,比如把這個包發送給訂閱該主題的接收端,並回複PUBACK包。The duplicate(DUP)flag,用來標記PUBLISH 被重新分發的情況。僅僅是為了內部使用的目的,並且當QoS 為1 是不會被broker 或者client處理。接受者都會發送PUBACK訊息,而不管DUP flag。
QoS=2時,它會確保每個訊息都只被接收到的一次,他是最安全也是最慢的服務等級。如果接收端接收到了一個QoS 的PUBLISH訊息,他會適當地處理這個訊息並發送一個PUBREC的包去通知broker。直到他發出一個PUBCOMP包為止,接收端都儲存這個包packet identifier。這一點很重要,因為它避免了二次處理同一個PUBLISH包。 當寄件者接收端PUBREC的時候,它可以放棄最開始的publish了,因為它已經知道另一端已經接收到訊息,他將儲存PUBREC並且回複PUBREL。當接收端接收到PUBREL,它就可以丟棄所有該包的儲存狀態並回複PUBCOMP。當發送端接收到PUBCOMP時也會總同樣的處理。
在這裡要注意一點,QoS流在發送端和接收端是兩件不同的事情,當然發送端與接收端QoS的等級也可以不一樣。在發送端與broker之間,發送端定義了QoS等級。當broker發送訊息到接收端是,接收端決定了QoS的等級。
到這裡MQTT一些重要的知識點就羅列得差不多了,還有一些具體的細節有需要的可以自行百度下MQTT的文檔(有中文的)