聶永的博客

          記錄工作/學(xué)習(xí)的點點滴滴。

          MQTT協(xié)議筆記之發(fā)布流程

          前言

          這次要講到客戶端/服務(wù)器的發(fā)布消息行為,與PUBLISH相關(guān)的消息類型,會在這里看到。

          PUBLISH

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

          消息架構(gòu)一覽:

           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,二進制對象形式。二進制具體包含的內(nèi)容和格式,可有應(yīng)用程序自身定義。若消息體為空(0長度)也是可能的。

          固定頭部

          DUP flag,設(shè)為0,表示當(dāng)前為第一次發(fā)送。

          RETAIN flag,只有在PUBLISH消息中才有效。

          • 1:表示發(fā)送的消息需要一直持久保存,不但要發(fā)送給當(dāng)前的訂閱者,并且以后新來的訂閱了此Topic name的訂閱者會馬上得到推送。 備注:新來乍到的訂閱者,只會取出最新的一個RETAIN flag = 1的消息推送,不是所有。
          • 0:僅僅為當(dāng)前訂閱者推送此消息。

          可變頭部

          Topic name,UTF-8編碼字符串形式,不支持通配符!

          消息體

          一般作為UTF-8編碼寫入接口,但不排除自定義的消息格式。

          空的消息體(zero-length)的PUBLISH消息也可以是合法的。

          當(dāng)服務(wù)器接收到空消息體(zero-length payload)、retain = 1、具有topic name的一個PUBLISH特殊消息,表示同時滿足retain = 1、相同topic name的這兩個特征的被持久化PUBLISH消息,可被刪除。

          Response/響應(yīng)

          固定頭部QoS level決定了消息中間件針對發(fā)布者具體需要響應(yīng)的內(nèi)容:

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

          備注:僅僅針對發(fā)布PUBLISH消息的發(fā)布者。

          Actions:

          無論是訂閱者還是服務(wù)器接收到PUBLISH消息之后,需要根據(jù)QoS level執(zhí)行不同動作。

          QoS Level Expected Action
          QoS 0 發(fā)送到所有感興趣者
          QoS 1 持久化記錄下來,發(fā)送到所有感興趣的參與者,返回一個PUBACK消息給發(fā)送者
          QoS 2 持久化記錄下來,暫時不發(fā)送所有感興趣的參與者,返回一個PUBREC消息給發(fā)送者

          如果服務(wù)器收到PUBLISH消息,參與者指的是訂閱者。如果訂閱者收到PUBLISH消息,參與者就是服務(wù)器。 需要注意:

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

          授權(quán)

          未經(jīng)授權(quán)的發(fā)布者提交的PUBLISH消息,服務(wù)器會忽略掉,客戶端不會被通知。

          PUBACK

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

           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,作為訂閱者/服務(wù)器對QoS level = 2的發(fā)布PUBLISH消息的發(fā)送方的響應(yīng),確認(rèn)已經(jīng)收到,為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

          無論是訂閱者還是服務(wù)器,在消費PUBREC消息之后需要發(fā)送一個PUBREL消息給發(fā)送者(和PUBREC具有同樣的消息ID),確認(rèn)已收到。

          PUBREL

          Qos level = 2的協(xié)議流的第三個消息,有PUBLISH消息的發(fā)布者發(fā)送,參與方接收。完整示范如下:

           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,表示消息第一次被發(fā)送。

          毫無疑問,剩余長度為2個byte長度。

          可變頭部中,消息ID和發(fā)布者接收到的PUBREC所包含的消息ID是一致的。

          動作:

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

          PUBCOMP

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

          完整的消息一覽,和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

          當(dāng)客戶端接收一個PUBCOMP消息時,客戶端摒棄原來的消息,因為它已經(jīng)成功發(fā)送消息到服務(wù)器。

          小結(jié)

          消息的發(fā)布和確認(rèn)等一些流程,主要是跟消息發(fā)布者所設(shè)定的QoS level有關(guān);稍加整理,繪制了下面一張圖,理解起來可能會更清晰些:

          Publish流程圖

          上圖針對的是客戶端發(fā)布消息到服務(wù)器端的方向。

          為了確保消息已經(jīng)成功傳遞過去,只有收到了確認(rèn),才會讓人特別放心。

          在QoS level = 2時,通信雙方都需要知道各自的確認(rèn)流程以及所處階段等,交互很多,數(shù)據(jù)量大的情況下,可能會造成數(shù)據(jù)線路傳遞擁塞。服務(wù)器選擇QoS = 0/1,大部分情況都是可以應(yīng)對的。 比如重要消息,就要確保對方都要收到,然后彼此確認(rèn),OK,這個消息是真實、有效的。

          無論Qos level為0、1,還是2,服務(wù)器(具備所有條件都滿足之后)總要把收到的具體內(nèi)容和topic組裝成一個新的PUBLISH Message(也不一定要重新構(gòu)造,但要求推送的PUBLISH消息,一定要具有明確的主題和內(nèi)容,RETAIN標(biāo)志不能設(shè)置為1)推送到所有感興趣的訂閱者。

          嗯,消息的發(fā)布來源別忘記還有可能來自CONNECT消息中的Will Topic和Will Message,若是設(shè)置了Will flag標(biāo)記的話。

          posted on 2014-02-10 23:42 nieyong 閱讀(17358) 評論(5)  編輯  收藏 所屬分類: MQTT

          評論

          # re: MQTT協(xié)議筆記之發(fā)布流程 2014-02-11 08:14 鵬達鎖業(yè)

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

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

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

          # re: MQTT協(xié)議筆記之發(fā)布流程 2016-12-27 09:00 Haven

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

          # re: MQTT協(xié)議筆記之發(fā)布流程 2017-01-05 15:20 nieyong

          @Haven

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

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

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

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

          好比雙發(fā)約定一件事:

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

          # re: MQTT協(xié)議筆記之發(fā)布流程 2017-01-10 13:03 Haven

          @nieyong
          謝謝兄弟的回復(fù),

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

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

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


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

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2017年1月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          統(tǒng)計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 兴安县| 介休市| 宁晋县| 精河县| 武胜县| 鄂托克旗| 栖霞市| 遂平县| 大化| 民县| 光山县| 潞城市| 南京市| 南雄市| 南部县| 兴业县| 六盘水市| 名山县| 广州市| 大竹县| 南召县| 蕲春县| 梅河口市| 金坛市| 镇安县| 柳江县| 仙居县| 高台县| 虞城县| 通州区| 元阳县| 平阴县| 舟曲县| 寿光市| 沧源| 葫芦岛市| 徐闻县| 井研县| 饶河县| 寻乌县| 清远市|