MQTT協(xié)議總結(jié)

MQTT Protocol

MQTT協(xié)議特性

一句話總結(jié):MQTT是一個(gè)簡單霎匈,輕量的消息發(fā)布/訂閱協(xié)議椭蹄。

MQTT報(bào)文結(jié)構(gòu)

一個(gè)MQTT報(bào)文主要由三部分組成:固定報(bào)頭(Fix Header)戏锹,可變報(bào)頭(Variable Header)和Payload斜棚。所有的報(bào)文都必須要有固定報(bào)頭糕篇,而可變報(bào)頭和Payload只有特定的消息才有啄育。

Structure

Fix Header

Fix Header使用一個(gè)Byte來標(biāo)識(shí),其中高四位用于控制報(bào)文類型拌消。所以挑豌,MQTT最多能夠表示16中報(bào)文類型。就目前v3.1.1版本來說墩崩,這4位并沒有完全占用氓英,還有兩個(gè)保留值,分別是0和15鹦筹。所以铝阐,目前MQTT有14種報(bào)文類型,下邊會(huì)展開介紹铐拐。下邊表格展示了每種報(bào)文類型其固定報(bào)頭的值:

Control Packets

Fix Header中低四位是標(biāo)志位(Flags)徘键,標(biāo)志位沒啥好說的,而且它們也基本是固定的遍蟋,我們大概看下不同的報(bào)文對(duì)應(yīng)的標(biāo)志位的值:

Fix Header

Variable Header

除了固定報(bào)頭啊鸭,MQTT還制定了可變報(bào)頭∧渲担可變報(bào)頭只存在于部分報(bào)文中,并且不同的報(bào)文類型其可變報(bào)頭也不一樣赂摆。比如PUBLISH(QoS > 0時(shí))挟憔, PUBACK,PUBREC烟号,PUBREL绊谭,PUBCOMP,SUBSCRIBE, SUBACK汪拥, UNSUBSCIBE达传,UNSUBACK這些報(bào)文擁有一個(gè)兩個(gè)字節(jié)長度的Package Identifier;CONNECT有四個(gè)可變報(bào)頭:Protocol Name,Protocol Level宪赶,Connect Flags宗弯,Keep Alive。

Payload

在可變報(bào)頭后搂妻,緊接著就是Payload蒙保。Payload也是部分報(bào)文擁有。比如PUBLISH欲主,用它來存儲(chǔ)推送的消息內(nèi)容邓厕;CONNECT消息可用它來存儲(chǔ)用戶名密碼,SUBSCRIBE可用它來存儲(chǔ)訂閱的主題名扁瓢,等等详恼。像PINGREQ,PINGRESP引几,PUBACK等這些消息就沒有PAYLOAD昧互。下表展示了不同消息其Payload的情況:

Payload

剩余長度 Remaining Length

剩余長度是除了Fix Header以及剩余長度本身之外的報(bào)文大小。即剩余長度=可變報(bào)頭長度+Payload長度她紫。MQTT規(guī)定用1~4個(gè)字節(jié)記錄報(bào)文的剩余長度硅堆。其中每個(gè)字節(jié)的最高位用來標(biāo)識(shí)是否有更多的數(shù)據(jù),這樣一個(gè)字節(jié)最大能表示數(shù)值128贿讹。4個(gè)字節(jié)是最大能表示268435455渐逃,也就是256M。

MQTT報(bào)文概覽

MQTT共有14種報(bào)文類型民褂,這節(jié)主要介紹一下這些報(bào)文的作用茄菊。成對(duì)出現(xiàn)的報(bào)文會(huì)放在同一小節(jié)。

CONNECT & CONNECTACK

CONNECT是客戶端第一個(gè)發(fā)送的消息赊堪∶嬷常客戶端和服務(wù)器端建立TCP鏈接之后,應(yīng)立即發(fā)送CONNECT消息哭廉。如果一段時(shí)間內(nèi)客戶端沒有向服務(wù)端發(fā)送CONNECT消息脊僚,那么服務(wù)端應(yīng)斷開這個(gè)鏈接。服務(wù)端在收到CONNECT消息之后遵绰,應(yīng)回復(fù)CONNECTACK消息辽幌。CONNECTACK消息包含了鏈接是否成功建立,或者為什么沒有建立成功椿访。

CONNECT指令相對(duì)復(fù)雜乌企,下邊我們?cè)敿?xì)介紹一下它包含的各部分內(nèi)容。

固定報(bào)頭

fix_header_connect.png

可變報(bào)頭

可變報(bào)頭內(nèi)容較多成玫,包含了以下四個(gè)字段:協(xié)議名(Protocol Name)加酵,協(xié)議級(jí)別(Protocol Leven)拳喻,鏈接標(biāo)志(Connect Flags),保持鏈接(Keep Alive)猪腕。

協(xié)議名是固定的冗澈,是以u(píng)tf-8編碼的MQTT,如果服務(wù)端發(fā)現(xiàn)協(xié)議名稱不對(duì)码撰,可以斷開當(dāng)前的鏈接渗柿,也可以繼續(xù)處理,但是不能按照MQTT協(xié)議處理該報(bào)文脖岛。

協(xié)議級(jí)別也是固定的朵栖,對(duì)于MQTT 3.1.1是0x04。如果服務(wù)端接受到的客戶端協(xié)議版本太低柴梆,則返回當(dāng)前服務(wù)端不支持的協(xié)議級(jí)別陨溅,并斷開當(dāng)前鏈接。

Connect Flags

Connect Flags也包含了多種信息:

connect_flags_connect.png

第0位是固定的保留位绍在,服務(wù)端會(huì)檢查這位是否為0门扇,如果不是則斷開鏈接。

第1位Clean Session偿渡,如果值為1的話表示服務(wù)端不會(huì)為客戶端保留任何Session信息臼寄。所以也不存在客戶端鏈接是恢復(fù)原有Session這一說。當(dāng)Clean Session為0時(shí)溜宽,如果服務(wù)端有與當(dāng)前Client關(guān)聯(lián)的Session吉拳,則基于當(dāng)前Session進(jìn)行通信;如果沒有則創(chuàng)建新的Session适揉。

我們看一下session都包含什么信息:

客戶端的會(huì)話狀態(tài)包括:
  • 已經(jīng)發(fā)送給服務(wù)端留攒,但是還沒有完成確認(rèn)的QoS 1和QoS 2級(jí)別的消息。
  • 已從服務(wù)端接收嫉嘀,但是還沒有完成確認(rèn)的QoS 2級(jí)別的消息炼邀。
服務(wù)端的會(huì)話狀態(tài)包括:
  • 會(huì)話是否存在,即使會(huì)話狀態(tài)的其它部分都是空剪侮。
  • 客戶端的訂閱信息拭宁。
  • 已經(jīng)發(fā)送給客戶端,但是還沒有完成確認(rèn)的QoS 1和QoS 2級(jí)別的消息瓣俯。
  • 即將傳輸給客戶端的QoS 1和QoS 2級(jí)別的消息红淡。
  • 已從客戶端接收,但是還沒有完成確認(rèn)的QoS 2級(jí)別的消息降铸。
  • 可選,準(zhǔn)備發(fā)送給客戶端的QoS 0級(jí)別的消息摇零。

遺囑

Will包含三部分:Will Flag是否在意外斷開時(shí)發(fā)布遺囑消息推掸;Will Qos 消息的服務(wù)等級(jí);Will Retain,是否保留谅畅。

什么情況下會(huì)發(fā)布遺囑消息:

  • 服務(wù)端檢測(cè)到了一個(gè)I/O錯(cuò)誤或者網(wǎng)絡(luò)故障登渣。
  • 客戶端在保持連接( Keep Alive) 的時(shí)間內(nèi)未能通訊。
  • 客戶端沒有先發(fā)送DISCONNECT報(bào)文直接關(guān)閉了網(wǎng)絡(luò)連接毡泻。
  • 由于協(xié)議錯(cuò)誤服務(wù)端關(guān)閉了網(wǎng)絡(luò)連接胜茧。

遺囑消息都是發(fā)生在服務(wù)端認(rèn)為客戶端與自己斷開了鏈接。遺囑存在的意義就是能夠讓其它客戶端及時(shí)的知道當(dāng)前鏈接已經(jīng)下線仇味。

Password和User Name

第6,7位是Password和User Name Flag呻顽。這些都比較簡單,如果有的話在Payload中填寫相應(yīng)的值即可丹墨。

說完CONNECT報(bào)文廊遍,我們來看一下CONNECTACK,CONNECT我們主要說兩個(gè)知識(shí)點(diǎn):鏈接返回碼贩挣,會(huì)話喉前。

鏈接返回碼

連接返回碼由可變報(bào)頭的第二個(gè)字節(jié)表示。

return_code.png

Session Present

CONNECTACK的的一個(gè)字節(jié)是Connect Acknowledge Flags(鏈接確認(rèn)標(biāo)志)王财。鏈接確認(rèn)標(biāo)志的第0位是Session Present卵迂。如果CONNECT的CleanSession標(biāo)志設(shè)置為1,SessionPresent需設(shè)置為0绒净。如果Clean Session設(shè)置為0见咒,如果服務(wù)端有關(guān)于當(dāng)前Client的Session,則Session Present設(shè)置為1疯溺,否則設(shè)置為0论颅。

PUBLISH & PUBACK

PUBLISH用于客戶端,服務(wù)端之間的消息推送囱嫩。PUBACK是一方收到PUBLISH之后向另一方發(fā)送應(yīng)答消息恃疯。下面我們先解釋一下PUBLISH消息。

固定報(bào)頭

publish-fix-header

然后publish是四個(gè)標(biāo)識(shí)位墨闲,由低到高分別是:Retain(消息是否保留)今妄,QoS(消息質(zhì)量等級(jí)),DUP(是否是舊報(bào)文重發(fā))鸳碧。

QoS

QoS標(biāo)識(shí)消息的服務(wù)級(jí)別盾鳞,MQTT規(guī)定了三種消息服務(wù)級(jí)別:
QoS 0:Fire and Forgot;
QoS 1:At Least Once瞻离;
QoS 2:Exectly Once腾仅。其中QoS2是最級(jí)別的協(xié)議。它需要經(jīng)過兩次服務(wù)端與客戶端的通信才能完成: PUBLISH <-> PUBREC套利,PUBREL <-> PUBCOMP

實(shí)際應(yīng)用中根據(jù)自己的應(yīng)用特點(diǎn)選擇不同的服務(wù)級(jí)別即可推励。

Retain

如果客戶端發(fā)送的retain標(biāo)識(shí)為1鹤耍,則服務(wù)端必須保存該條消息以及它的QoS。以便這個(gè)topic有新的訂閱者訂閱時(shí)验辞,服務(wù)端要把這個(gè)消息推送給它稿黄。使用Retain的好處就是新的訂閱者訂閱成功之后便能得到最近的一條消息,無需等到下次產(chǎn)生消息時(shí)跌造。

注意在協(xié)議文檔中說道:When a new subscription is established, the last retained message, if any, on each matching topic name MUST be sent to the subscriber.杆怕。所以,每個(gè)retain 消息都會(huì)覆蓋上一條壳贪,把這條消息最為最新保留消息陵珍。

如果服務(wù)器收到發(fā)送retain為true,payload為空的消息撑碴,它會(huì)把這個(gè)topic保留的retain消息刪除撑教。

如果服務(wù)器收到的 QoS 0 消息的保留標(biāo)志設(shè)置為 1, 則它必須丟棄以前為該主題保留的任何消息。它應(yīng)該將新的 QoS 0 消息存儲(chǔ)為該主題的新保留消息, 但在任何時(shí)候都可以選擇丟棄它, 如果發(fā)生這種情況, 該主題將不會(huì)有保留消息醉拓。

可變報(bào)頭

報(bào)頭包含了Topic Name和Packet Identifier伟姐。當(dāng)QoS為1或2時(shí)Packaet Identifier才有,Packet Identifier可以重復(fù)利用亿卤,只要消息被確認(rèn)它的Packet Identifier便可被其他消息使用愤兵。Packet Identifier最大占用兩位,最大數(shù)值65536排吴。

PUBLISH & PUBREC & PUBREL & PUBLCOMP

如果QoS等級(jí)為2的話客戶端和服務(wù)端要經(jīng)過兩個(gè)來回的通信過程:PUBLISH <-> PUBREC秆乳,PUBREL <-> PUBCOMP。這樣可以實(shí)消息Exactly Once推送钻哩。

SUBSCRIBE & SUBACK

SUBSCRIBE表示客戶端向服務(wù)端訂閱訂閱感興趣的一個(gè)或多個(gè)主題屹堰。服務(wù)端會(huì)維護(hù)主題和訂閱關(guān)系,如果多個(gè)客戶端訂閱了同一個(gè)主題街氢,其中任何一個(gè)客戶端發(fā)送消息時(shí)扯键,服務(wù)端需要把這個(gè)消息PUBLISH給其他訂閱客戶端。當(dāng)服務(wù)端收到SUBSCRIBE時(shí)它會(huì)立即回復(fù)SUBACK珊肃。

UNSUBSCRIBE & UNSUBACK

這兩個(gè)消息用于取消訂閱和取消訂閱確認(rèn)荣刑。

PINGREQ & PINGRESP

PINGREQ,PINGRESP是客戶端和服務(wù)端之間的心跳檢測(cè)伦乔。在CONNECT命令里厉亏,會(huì)設(shè)置keepalive時(shí)間,如果在keepalive 1.5倍時(shí)間內(nèi)服務(wù)端沒有收到任何客戶端消息則會(huì)把該客戶端強(qiáng)制斷開烈和。因此如果客戶端在沒有其它消息向服務(wù)端發(fā)送時(shí)爱只,應(yīng)該定時(shí)在合理的時(shí)間內(nèi)向服務(wù)器發(fā)送PINGREQ指令。服務(wù)端收到該指令后會(huì)回復(fù)PINGRESP招刹√袷裕客戶端如果在合理的時(shí)間內(nèi)沒有收到響應(yīng)則應(yīng)關(guān)閉鏈接沥匈。

DISCONNECT

這是客戶端發(fā)送給服務(wù)端的最后一個(gè)命令。在發(fā)送了這個(gè)命令之后客戶端應(yīng)該立即斷開鏈接忘渔,并且不能通過這個(gè)鏈接再發(fā)送任何消息。服務(wù)端在收到這個(gè)消息之后缰儿,刪除與當(dāng)前鏈接關(guān)聯(lián)的未發(fā)布的遺囑消息畦粮,如果客戶端還沒斷開鏈接,服務(wù)端關(guān)閉鏈接乖阵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宣赔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瞪浸,更是在濱河造成了極大的恐慌儒将,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件对蒲,死亡現(xiàn)場(chǎng)離奇詭異钩蚊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蹈矮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門砰逻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泛鸟,你說我怎么就攤上這事蝠咆。” “怎么了北滥?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵刚操,是天一觀的道長。 經(jīng)常有香客問我再芋,道長菊霜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任祝闻,我火速辦了婚禮占卧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘联喘。我一直安慰自己华蜒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布豁遭。 她就那樣靜靜地躺著叭喜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蓖谢。 梳的紋絲不亂的頭發(fā)上捂蕴,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天譬涡,我揣著相機(jī)與錄音,去河邊找鬼啥辨。 笑死涡匀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溉知。 我是一名探鬼主播陨瘩,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼级乍!你這毒婦竟也來了舌劳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤玫荣,失蹤者是張志新(化名)和其女友劉穎甚淡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捅厂,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贯卦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恒傻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脸侥。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盈厘,靈堂內(nèi)的尸體忽然破棺而出睁枕,到底是詐尸還是另有隱情,我是刑警寧澤沸手,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布外遇,位于F島的核電站,受9級(jí)特大地震影響契吉,放射性物質(zhì)發(fā)生泄漏跳仿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一捐晶、第九天 我趴在偏房一處隱蔽的房頂上張望菲语。 院中可真熱鬧,春花似錦惑灵、人聲如沸山上。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽佩憾。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妄帘,已是汗流浹背楞黄。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抡驼,地道東北人鬼廓。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像致盟,于是被迫代替她去往敵國和親桑阶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容