聶永的博客

          記錄工作/學習的點點滴滴。

          MQTT協議筆記之發布流程

          前言

          這次要講到客戶端/服務器的發布消息行為,與PUBLISH相關的消息類型,會在這里看到。

          PUBLISH

          客戶端發布消息經由服務器分發到所有對應的訂閱者那里。一個訂閱者可以訂閱若干個主題(Topic name),但一個PUBLISH消息只能擁有一個主題。

          消息架構一覽:

           Description76543210
          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消息,參與者就是服務器。 需要注意:

          1. 發布者發布的PUBLISH消息發送到服務器,在payload/消息體處可能夾帶有私貨,可能含有自定義的數據 格式
          2. 若兼容MQTT客戶端,經由服務器分發到所有對應訂閱者處只能是規規矩矩的PUBLISH消息,并且固定頭部的RETAIN標志不能被設置成有效值1

          授權

          未經授權的發布者提交的PUBLISH消息,服務器會忽略掉,客戶端不會被通知。

          PUBACK

          作為訂閱者/服務器接收(QoS level = 1)PUBLISH消息之后對發送者的響應,整個消息不復雜。

           Description76543210
          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相比,除了消息類型不同外,其它都是一樣。

           Description76543210
          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消息的發布者發送,參與方接收。完整示范如下:

           Description76543210
          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是一致的。

          動作:

          1. 服務器接收到發布者(a)的PUBREL消息,此時服務器讓發布者(a)剛才發布PUBLISH消息可用,發送此PUBLISH消息給所有訂閱此主題的訂閱者,然后發送PUBCOMP消息給發布者(a)
          2. 可變頭部包含消息ID和服務器接收的PUBREL消息ID是一致的。 一個訂閱者接收到PUBREL消息,訂閱者使PUBLISH消息可用,然后反饋一個PUBCOMP消息給服務器

          PUBCOMP

          作為QoS level = 2消息流第四個,也是最后一個消息,由收到PUBREL的一方向另一方做出的響應消息。

          完整的消息一覽,和PUBREL一致,除了消息類型。

           Description76543210
          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有關;稍加整理,繪制了下面一張圖,理解起來可能會更清晰些:

          Publish流程圖

          上圖針對的是客戶端發布消息到服務器端的方向。

          為了確保消息已經成功傳遞過去,只有收到了確認,才會讓人特別放心。

          在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

          評論

          # re: MQTT協議筆記之發布流程 2014-02-11 08:14 鵬達鎖業

          期待博主更新文章。。。加油
            回復  更多評論   

          # re: MQTT協議筆記之發布流程[未登錄] 2015-10-26 16:56 123

          請問,在服務器端,用代理轉發的方式。是一個SUB訂閱多個訂閱號(多個設備的ID)->myaql 方式合理;還是實現多線程SUB,每一個線程的SUB訂閱一個ID在同步到mysql的方式合理。  回復  更多評論   

          # re: MQTT協議筆記之發布流程 2016-12-27 09:00 Haven

          博主牛人呀,有一個QoS2的問題請教,為什么QoS2需要4次包,2次不就可以了嗎?還望回復。  回復  更多評論   

          # re: MQTT協議筆記之發布流程 2017-01-05 15:20 nieyong

          @Haven

          兄弟,針對QoS2,為了便于說明,我們先假設一個方向,Server -> Client:

          ----PUBLISH--->
          <----PUBREC----
          ----PUBREL---->
          <----PUBCOMP---

          1. Server發送PUBLISH消息到Client,Client接收之后需要確認收到嘛,就返回PUBREC吧;但此時Client僅僅是把數據發送出去了而已,至于Server端收不收到那就不得而知
          2. Server接收ClientPUBREC消息之后,需要回一個PUBREL消息告訴Client自己收到啦,同樣道理也僅僅只是發送出去,Client是不是能收到的這個響應,心里面也沒譜呀
          3. Client收到來自Server的PUBREL之后,就非常明白自己針對PUBLISH消息做出的PUBREC響應消息在Server端是已經收到啦,但是需要告訴Server,自己收到它的再三確認啦
          4. Server端此時等待Client上報PUBCOMP消息,一旦接收到之后,表示針對某個消息雙方都再三確認了,這事就沒有問題啦

          其核心所設定網絡是不靠譜的,任何一次發送數據到對端,都有可能因收不到(比如發送之后,某一端斷網啦,或中間路由設備因為容量滿了拋棄啦)。

          好比雙發約定一件事:

          Server - 我給你說說這件事....
          Client - 我同意了你這樣做。
          Server - 你確定你同意了?
          Client - 是的,我同意了。
          Server - OK,那這事就這么定了,我知道該怎么做啦。  回復  更多評論   

          # re: MQTT協議筆記之發布流程 2017-01-10 13:03 Haven

          @nieyong
          謝謝兄弟的回復,

          其實我還是覺得兩次就可以搞定了。同樣以Server -> Client為例

          1. Server發送PUBLISH消息到Client,Client接收之后需要確認收到嘛,就返回PUBREC吧;但此時Client僅僅是把數據發送出去了而已,至于Server端收不收到那就不得而知.
          2. Server可能收到了PUBREC,也可能沒有收到
          a. Server收到了PUBREC, 這時候就表示Client收到消息了,表示成功遞送消息了。
          b. Server沒有收到PUBREC,等待一定時間后,重發PUBLISH即可。

          在1中,Client收到PUBLISH后就把數據保存在數據庫中,如果收到重復PUBLISH重數據庫就可以知道是重復數據。
          在2中,超時就重傳PUBLISH即可。
          感覺這樣兩步完全滿足QoS2了呀!!


          其實我在設計一套私有IM協議,用于自己的App中,希望能加你QQ探討一下MQTT的QoS2問題。
          我的QQ:357545146  回復  更多評論   

          公告

          所有文章皆為原創,若轉載請標明出處,謝謝~

          新浪微博,歡迎關注:

          導航

          <2016年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 永昌县| 中卫市| 新河县| 荆州市| 石棉县| 湘潭市| 崇文区| 宁都县| 汶川县| 巩留县| 晋城| 贵港市| 孝感市| 白水县| 山东省| 陆河县| 尉氏县| 普格县| 北川| 汉阴县| 定襄县| 鄂尔多斯市| 景泰县| 策勒县| 石楼县| 托克逊县| 历史| 阿图什市| 甘德县| 乡城县| 聊城市| 河北区| 楚雄市| 彰化县| 新兴县| 马公市| 故城县| 汉寿县| 临泽县| 武清区| 盐城市|