<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    聶永的博客

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

    MQTT協(xié)議筆記之消息流

    前言

    前面的筆記已把所有消息類型都過了一遍,這里從消息流的角度嘗試解讀一下。

    網(wǎng)絡(luò)故障

    在任何網(wǎng)絡(luò)環(huán)境下,都會出現(xiàn)一方連接失敗,比如離開公司大門那一刻沒有了WIFI信號。但持續(xù)連接的另一端-服務(wù)器可能不能立即知道對方已斷開。類似網(wǎng)絡(luò)異常情況,都有可能在消息發(fā)送的過程中出現(xiàn),消息發(fā)送出去,就丟失了。

    MQTT協(xié)議假定客戶端和服務(wù)器端穩(wěn)定情況一般,彼此之通信管道不可靠,一旦客戶端網(wǎng)絡(luò)斷開,情況就會很嚴(yán)重,很難恢復(fù)原狀。

    但別忘記,很多客戶端會有永久性存儲設(shè)備支持,比如閃存ROM、存儲卡等,在通信出現(xiàn)異常的情況下可以用于保存關(guān)鍵數(shù)據(jù)或狀態(tài)信息等。

    總之,異常網(wǎng)絡(luò)情況很復(fù)雜,只能小心處理之。

    消息重發(fā)策略

    QoS > 0情況下,PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE等類型消息在發(fā)送者發(fā)送完之后,需要等待一個響應(yīng)消息,若在一個指定時間段內(nèi)沒有收到,發(fā)送者可能需要重試。重發(fā)的消息,要求DUP標(biāo)記要設(shè)置為1.

    等待響應(yīng)的超時應(yīng)該在消息成功發(fā)送之后開始算起,并且等待超時應(yīng)該是可以配置選項(xiàng),以便在下一次重試的時候,適當(dāng)加大。比如第一次重試超時10秒,下一次可能為20秒,再一次重試可能為60秒呢。當(dāng)然,還要有一個重試次數(shù)限制的。

    還有一種情況,客戶端重新連接,但未在可變頭部中設(shè)置clean session標(biāo)記,但雙方(客戶端和服務(wù)器端)都應(yīng)該重試先前未發(fā)送的動態(tài)消息(in-flight messages)。客戶端不被強(qiáng)制要求發(fā)送未被確認(rèn)的消息,但服務(wù)器端就得需要重發(fā)那些未被去確認(rèn)的消息。

    QoS level決定的消息流

    QoS level為Quality of Service level的縮寫,翻譯成中文,服務(wù)質(zhì)量等級。

    MQTT 3.1協(xié)議在"4.1 Quality of Service levels and flows"章節(jié)中,僅僅討論了客戶端到服務(wù)器的發(fā)布流程,不太完整。因?yàn)闆Q定消息到達(dá)率,能夠提升發(fā)送質(zhì)量的,應(yīng)該是服務(wù)器發(fā)布PUBLISH消息到訂閱者這一消息流方向。

    QoS level 0

    至多發(fā)送一次,發(fā)送即丟棄。沒有確認(rèn)消息,也不知道對方是否收到。

    Client Message and direction Server
    QoS = 0 PUBLISH
    ---------->
    Action: Publish message to subscribers then Forget
    Reception: <=1

    針對的消息不重要,丟失也無所謂。

    網(wǎng)絡(luò)層面,傳輸壓力小。

    QoS level 1

    所有QoS level 1都要在可變頭部中附加一個16位的消息ID。

    SUBSCRIBE和UNSUBSCRIBE消息使用QoS level 1。

    針對消息的發(fā)布,Qos level 1,意味著消息至少被傳輸一次。

    發(fā)送者若在一段時間內(nèi)接收不到PUBACK消息,發(fā)送者需要打開DUB標(biāo)記為1,然后重新發(fā)送PUBLISH消息。因此會導(dǎo)致接收方可能會收到兩次PUBLISH消息。針對客戶端發(fā)布消息到服務(wù)器的消息流:

    Client Message and direction Server
    QoS = 1
    DUP = 0
    Message ID = x

    Action: Store message

    PUBLISH
    ---------->
    Actions:
    • Store message

    • Publish message to subscribers
    • Delete message

    Reception: >=1
    Action: Discard message PUBACK
    <----------
    Message ID = x

    針對服務(wù)器發(fā)布到訂閱者的消息流:

    Server Message and direction Subscriber
    QoS = 1
    DUP = 0
    Message ID = x
    PUBLISH
    ---------->
    Actions:
    • Store message

    • Make message available                       
    Reception: >=1

    PUBACK
    <----------
    Message ID = x

    發(fā)布者(客戶端/服務(wù)器)若因種種異常接收不到PUBACK消息,會再次重新發(fā)送PUBLISH消息,同時設(shè)置DUP標(biāo)記為1。接收者以服務(wù)器為例,這可能會導(dǎo)致服務(wù)器收到重復(fù)消息,按照流程,broker(服務(wù)器)發(fā)布消息到訂閱者(會導(dǎo)致訂閱者接收到重復(fù)消息),然后發(fā)送一條PUBACK確認(rèn)消息到發(fā)布者。

    在業(yè)務(wù)層面,或許可以彌補(bǔ)MQTT協(xié)議的不足之處:重試的消息ID一定要一致接收方一定判斷當(dāng)前接收的消息ID是否已經(jīng)接受過

    但一樣不能夠完全確保,消息一定到達(dá)了。

    QoS level 2

    僅僅在PUBLISH類型消息中出現(xiàn),要求在可變頭部中要附加消息ID。

    級別高,通信壓力稍大些,但確保了僅僅傳輸接收一次。

    先看協(xié)議中流程圖,Client -> Server方向,會有一個總體印象:

    Client Message and direction Server
    QoS = 2
    DUP = 0
    Message ID = x

    Action: Store message

    PUBLISH
    ---------->
    Action(a) Store message

    or

    Actions(b):
    • Store message ID
    • Publish message to subscribers
      PUBREC
    <----------
    Message ID = x
    Message ID = x PUBREL
    ---------->
    Actions(a):
    • Publish message to subscribers
    • Delete message

    or

    Action(b): Delete message ID
    Action: Discard message PUBCOMP
    <----------
    Message ID = x

    Server -> Subscriber

    Server Message and direction Subscriber
    QoS = 2
    DUP = 0
    Message ID = x
    PUBLISH
    ---------->
    Action: Store message
      PUBREC
    <----------
    Message ID = x
    Message ID = x PUBREL
    ---------->
    Actions:
    • Make message available                       

    PUBCOMP
    <----------
    Message ID = x

    Server端采取的方案a和b,都包含了何時消息有效,何時處理消息。兩個方案二選一,Server端自己決定。但無論死采取哪一種方式,都是在QoS level 2協(xié)議范疇下,不受影響。若一方?jīng)]有接收到對應(yīng)的確認(rèn)消息,會從最近一次需要確認(rèn)的消息重試,以便整個(QoS level 2)流程打通。

    消息順序

    消息順序會受許多因素的影響,但對于服務(wù)器程序,必須保證消息傳遞流程的每個階段要和開始的順序一致。例如,在QoS level 2定義的消息流中,PUBREL流必須和PUBLISH流具有相同的順序發(fā)送:

    Client Message and direction Server
      PUBLISH 1
    ---------->
    PUBLISH 2
    ---------->
    PUBLISH 3
    ---------->
     
      PUBREC 1
    <----------
    PUBREC 2
    <----------
     
      PUBREL 1
    ---------->
     
      PUBREC 3
    <----------
     
      PUBREL 2
    ---------->
     
      PUBCOMP 1
    <----------
     
      PUBREL 3
    ---------->
     
      PUBCOMP 2
    <----------
    PUBCOMP 3
    <----------
     

    流動消息(in-flight messages)數(shù)量允許有一個可保證的效果:

    • 在流動消息(in-flight)窗口1中,每個傳遞流在下一個流開始之前完成。這保證消息以提交的順序傳遞
    • 在流動消息(in-flight)大于1的窗口,只能在QoS level內(nèi)被保證消息的順序

    消息的持久化

    在MQTT協(xié)議中,PUBLISH消息固定頭部RETAIN標(biāo)記,只有為1才要求服務(wù)器需要持久保存此消息,除非新的PUBLISH覆蓋。

    對于持久的、最新一條PUBLISH消息,服務(wù)器不但要發(fā)送給當(dāng)前的訂閱者,并且新的訂閱者(new subscriber,同樣需要訂閱了此消息對應(yīng)的Topic name)會馬上得到推送。

    Tip:新來乍到的訂閱者,只會取出最新的一個RETAIN flag = 1的消息推送,不是所有。
    

    消息流的編碼/解碼

    MQTT協(xié)議中,由目前定義的14種類型消息在客戶端和服務(wù)器端之間數(shù)據(jù)進(jìn)行交互。若以JAVA語言構(gòu)建MQTT服務(wù)器,可選擇Netty作為基礎(chǔ)。

    在Netty中,數(shù)據(jù)的進(jìn)入和流出,代表了一次完整的交互。無論是要進(jìn)入的還是要流出的數(shù)據(jù)(單獨(dú)以服務(wù)器為例),都可看做字節(jié)流。若把每種類型消息抽象為一個具體對象,那么處理起來就不難了。

    客戶端->服務(wù)器,進(jìn)入的字節(jié)流,逐個字節(jié)/單位讀取,可還原成一個具體的消息對象(解碼的過程)。

    要發(fā)送到客戶端的消息對象,轉(zhuǎn)換(編碼)成字節(jié)流,然后由TCP通道流轉(zhuǎn)到接收者。

    小結(jié)

    斷斷續(xù)續(xù)記錄了MQTT 3.1協(xié)議的若干閱讀筆記,總之是把協(xié)議個人認(rèn)為不夠清晰,或者我不好理解的地方,著重進(jìn)行了分析。也便于自己以后回過來頭來翻閱,不是那么快的忘卻。

    posted on 2014-02-15 19:17 nieyong 閱讀(41534) 評論(9)  編輯  收藏 所屬分類: MQTT

    評論

    # re: MQTT協(xié)議筆記之消息流 2014-02-16 08:36 零柒鎖業(yè)

    期待更新啊  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2014-02-17 10:19 零柒鎖業(yè)

    支持博主分享  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2014-02-18 10:07 零柒鎖業(yè)

    期待更新啊  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2014-02-18 16:29 垂直綠化

    學(xué)習(xí)了。  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2014-02-28 14:59 依然清風(fēng)

    最好是能有源碼的體現(xiàn)
    現(xiàn)在主要困惑在主題那塊
    比如說A,B是兩個client,A 要接受B的消息,是不是應(yīng)該這樣,B發(fā)布一個主題,并且要還有A感興趣的消息,那么B發(fā)布到S(broke),然后A 要向S訂閱吧,等B的此類消息一到,就轉(zhuǎn)發(fā)給A是不是這個流程?  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2014-03-06 16:23 nieyong

    @依然清風(fēng)
    要非常清楚總體協(xié)議,代碼不過是在實(shí)現(xiàn)協(xié)議。
    Client A與Client B,在邏輯上不存在轉(zhuǎn)發(fā)。
    1. Client A在Broker上訂閱/注冊Topic M
    2. Broker接收包含Topic M的消息,檢索所有訂閱Topic M的客戶端
    3. Broker逐一會發(fā)送給所有訂閱Topic M訂閱者/客戶端,包括Client A  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2014-03-19 11:25 zyn

    分析的很好啊,之前看了個博客,看的頭暈暈的。看了你的表格描述,慢清楚的 謝謝  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2015-02-27 14:41 MR.zhang

    如果設(shè)置了消息的持久化,那么那些在緩存中的topic什么時間清楚,能控制不能,會不會因?yàn)榫彺嫣喽加么罅康膬?nèi)存  回復(fù)  更多評論   

    # re: MQTT協(xié)議筆記之消息流 2016-04-22 16:43 讓他一人

    瑩爾特瑞特人問題而天然  回復(fù)  更多評論   

    公告

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

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

    導(dǎo)航

    <2014年2月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    2324252627281
    2345678

    統(tǒng)計

    常用鏈接

    留言簿(58)

    隨筆分類(130)

    隨筆檔案(151)

    個人收藏

    最新隨筆

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 中文字幕无码不卡免费视频| 亚洲成人国产精品| 噼里啪啦免费观看高清动漫4| 中文字幕无码免费久久| a级毛片在线免费看| 99爱在线观看免费完整版| 三年片在线观看免费观看高清电影 | 热久久这里是精品6免费观看| 日本一道本不卡免费| 日本成人免费在线| 国产精品亚洲аv无码播放| 亚洲国产韩国一区二区| 一本久久免费视频| 无人在线直播免费观看| 久久99亚洲综合精品首页| 亚洲一区中文字幕在线观看| 国内成人精品亚洲日本语音| 日本一道本不卡免费| 四虎影视永久免费视频观看| 久久亚洲精品国产精品| 羞羞视频免费网站日本| 在线观看免费人成视频色9| 久久久久亚洲AV无码专区桃色| 亚洲人成在久久综合网站| 免费国产在线视频| 国产精品V亚洲精品V日韩精品| 香蕉大伊亚洲人在线观看| 国产在线观看麻豆91精品免费| 亚洲欭美日韩颜射在线二| 妇女自拍偷自拍亚洲精品| 大学生一级毛片免费看| 亚洲网址在线观看| 91麻豆国产免费观看| 亚洲bt加勒比一区二区| aaa毛片视频免费观看| 在线观看亚洲天天一三视| 亚州**色毛片免费观看| 久久久亚洲精品蜜桃臀| 国产精品hd免费观看| 亚洲无人区午夜福利码高清完整版| 特级毛片A级毛片免费播放|