本文主要介紹 MQTT 協(xié)議中發(fā)布訂閱的詳細(xì)過程。
1、Connect(連接)
MQTT 協(xié)議基于 TCP/IP 協(xié)議,MQTT Broker 和 Client 都有需要有 TCP/IP 地址。Client 連接?MQTT Broker 時(shí)有如下相關(guān)配置項(xiàng):
Client ID
服務(wù)端使用 ClientId 識(shí)別客戶端。連接服務(wù)端的每個(gè)客戶端都有唯一的 ClientId ??蛻舳撕头?wù)端都必須使用 ClientId 識(shí)別兩者之間的?MQTT 會(huì)話相關(guān)的狀態(tài)。
ClientId 必須存在,但是服務(wù)端可以允許客戶端提供一個(gè)零字節(jié)的 ClientId,如果這樣做了,服務(wù)端必須將這看作特殊情況并分配唯一的 ClientId 給那個(gè)客戶端。然后正常處理這個(gè) CONNECT 報(bào)文。
Username/Password
MQTT 可以通過發(fā)送用戶名和密碼來進(jìn)行相關(guān)的認(rèn)證和授權(quán),但是,如果此信息未加密,則用戶名和密碼是以明文的方式發(fā)送的。
Keep Alive
保持連接(Keep Alive)是一個(gè)以秒為單位的時(shí)間間隔,它是指在客戶端傳輸完成一個(gè)控制報(bào)文的時(shí)刻到發(fā)送下一個(gè)報(bào)文的時(shí)刻,兩者之間允許空閑的最大時(shí)間間隔??蛻舳素?fù)責(zé)保證控制報(bào)文發(fā)送的時(shí)間間隔不超過保持連接的值。如果沒有任何其它的控制報(bào)文可以發(fā)送,客戶端必須發(fā)送一個(gè) PINGREQ 報(bào)文。
如果 Keep Alive 的值非零,并且服務(wù)端在一點(diǎn)五倍的 Keep Alive 時(shí)間內(nèi)沒有收到客戶端的控制報(bào)文,它必須斷開客戶端的網(wǎng)絡(luò)連接,認(rèn)為網(wǎng)絡(luò)連接已斷開。
Clean Session
客戶端和服務(wù)端可以保存會(huì)話狀態(tài),以支持跨網(wǎng)絡(luò)連接的可靠消息傳輸,這個(gè)標(biāo)志告訴服務(wù)器這次連接是不是一個(gè)全新的連接。
客戶端的會(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í)別的消息。
如果 CleanSession 標(biāo)志被設(shè)置為 1,客戶端和服務(wù)端必須丟棄之前的任何會(huì)話并開始一個(gè)新的會(huì)話。會(huì)話僅持續(xù)和網(wǎng)絡(luò)連接同樣長的時(shí)間。
如果 CleanSession 標(biāo)志被設(shè)置為 0,服務(wù)端必須基于當(dāng)前會(huì)話(使用 ClientId 識(shí)別)的狀態(tài)恢復(fù)與客戶端的通信。如果沒有與這個(gè)客戶端標(biāo)識(shí)符關(guān)聯(lián)的會(huì)話,服務(wù)端必須創(chuàng)建一個(gè)新的會(huì)話。當(dāng)連接斷開后,客戶端和服務(wù)端必須保存會(huì)話信息。
2、Connack(確認(rèn)連接請(qǐng)求)
客戶端發(fā)送 Connect 報(bào)文請(qǐng)求對(duì)服務(wù)器的連接,服務(wù)器必須發(fā)送 Connack 報(bào)文作為對(duì) 來自客戶端的 Connect 報(bào)文的回應(yīng)。如果客戶端在合理的時(shí)間內(nèi)沒有收到服務(wù)端的CONNACK報(bào)文,客戶端應(yīng)該關(guān)閉網(wǎng)絡(luò)連接。合理的時(shí)間取決于應(yīng)用的類型和通信基礎(chǔ)設(shè)施。
Connack 報(bào)文包含 Session Present 和 Connect Return code 兩個(gè)重要的標(biāo)志。
Session Present
Session Present 標(biāo)志表示當(dāng)前會(huì)話是否是一個(gè)新的會(huì)話,如果服務(wù)端收到 CleanSession 標(biāo)志為1的連接,Connack報(bào)文中的 SessionPresent 標(biāo)志為 0 。如果服務(wù)端收到一個(gè) CleanSession 為0的連接,SessionPresent 標(biāo)志的值取決于服務(wù)端是否已經(jīng)保存了 ClientId 對(duì)應(yīng)客戶端的會(huì)話狀態(tài)。如果服務(wù)端已經(jīng)保存了會(huì)話狀態(tài),Connack 報(bào)文中的 SessionPresent 標(biāo)志為 1,如果服務(wù)端沒有已保存的會(huì)話狀態(tài),Connack 報(bào)文中的 SessionPresent 標(biāo)志為 0.
Connect Return code
Connect Return code 表示服務(wù)器對(duì)此次 Connect 的回應(yīng),0 表示連接已被服務(wù)器接受。如果服務(wù)端收到一個(gè)合法的 CONNECT 報(bào)文,但出于某些原因無法處理它,服務(wù)端應(yīng)該嘗試發(fā)送一個(gè)包含非零返回碼(表格中的某一個(gè))的 CONNACK 報(bào)文。如果服務(wù)端發(fā)送了一個(gè)包含非零返回碼的CONNACK 報(bào)文,那么它必須關(guān)閉網(wǎng)絡(luò)連接。
值 | 返回碼響應(yīng) | 描述 |
---|---|---|
0 | 0x00連接已接受 | 連接已被服務(wù)端接受 |
1 | 0x01連接已拒絕,不支持的協(xié)議版本 | 服務(wù)端不支持客戶端請(qǐng)求的MQTT協(xié)議級(jí)別 |
2 | 0x02連接已拒絕,不合格的客戶端標(biāo)識(shí)符 | 客戶端標(biāo)識(shí)符是正確的UTF-8編碼,但服務(wù)端不允許使用 |
3 | 0x03連接已拒絕,服務(wù)端不可用 | 網(wǎng)絡(luò)連接已建立,但MQTT服務(wù)不可用 |
4 | 0x04連接已拒絕,無效的用戶名或密碼 | 用戶名或密碼的數(shù)據(jù)格式無效 |
5 | 0x05連接已拒絕,未授權(quán) | 客戶端未被授權(quán)連接到此服務(wù)器 |
6-255 | ? | 保留 |
如果認(rèn)為上表中的所有連接返回碼都不太合適,那么服務(wù)端必須關(guān)閉網(wǎng)絡(luò)連接,不需要發(fā)送CONNACK 報(bào)文。
3、Subscribe(訂閱主題)
客戶端向服務(wù)端發(fā)送 Subscribe 報(bào)文用于創(chuàng)建一個(gè)或多個(gè)訂閱。每個(gè)訂閱注冊(cè)客戶端關(guān)心的一個(gè)或多個(gè)主題。為了將應(yīng)用消息轉(zhuǎn)發(fā)給與那些訂閱匹配的主題,服務(wù)端發(fā)送 Publish 報(bào)文給客戶端。Subscribe 報(bào)文為每個(gè)訂閱指定了最大的 QoS 等級(jí),服務(wù)端根據(jù)這個(gè)發(fā)送應(yīng)用消息給客戶端。
Subscribe 報(bào)文的有效載荷必須包含至少一對(duì)主題過濾器 和 QoS 等級(jí)字段組合。沒有有效載荷的 Subscribe 報(bào)文是違反協(xié)議的。
4、Suback(訂閱確認(rèn))
服務(wù)端發(fā)送 Suback 報(bào)文給客戶端,用于確認(rèn)它已收到并且正在處理 Subscribe 報(bào)文。
Suback 報(bào)文包含一個(gè)原因碼列表,用于指定授予的最大QoS等級(jí)或 Subscribe 報(bào)文所請(qǐng)求的每個(gè)訂閱發(fā)生的錯(cuò)誤,每個(gè)原因碼對(duì)應(yīng) Subscribe 報(bào)文中的一個(gè)主題過濾器。Suback 報(bào)文中的原因碼順序必須與 Subscribe 報(bào)文中的主題過濾器順序相匹配。
允許的返回碼值:
- 0x00 - 最大QoS 0
- 0x01 - 成功 – 最大QoS 1
- 0x02 - 成功 – 最大 QoS 2
- 0x80 - Failure 失敗
5、Publish(發(fā)布消息)
Publish 報(bào)文是指從客戶端向服務(wù)端或者服務(wù)端向客戶端傳輸一個(gè)應(yīng)用消息,服務(wù)器收到 Publish 報(bào)文后根據(jù)主題過濾器將消息轉(zhuǎn)發(fā)給其他客戶端。
發(fā)布消息時(shí)有如下配置項(xiàng):
Topic
主題名(Topic Name)用于識(shí)別消息應(yīng)該被發(fā)布到哪一個(gè)會(huì)話,服務(wù)端發(fā)送給訂閱客戶端的 Publish 報(bào)文的主題名必須匹配該訂閱的主題過濾器。
QoS
QoS 表示應(yīng)用消息分發(fā)的服務(wù)質(zhì)量等級(jí)保證
QoS值 | Bit 2 | Bit 1 | 描述 |
---|---|---|---|
0 | 0 | 0 | 最多分發(fā)一次 |
1 | 0 | 1 | 至少分發(fā)一次 |
2 | 1 | 0 | 只分發(fā)一次 |
- | 1 | 1 | 保留位 |
Publish 報(bào)文不能將 QoS 所有的位設(shè)置為 1。如果服務(wù)端或客戶端收到 QoS 所有位都為 1 的 Publish 報(bào)文,它必須關(guān)閉網(wǎng)絡(luò)連接。
Retain
如果客戶端發(fā)給服務(wù)端的 Publish 報(bào)文的保留(RETAIN)標(biāo)志被設(shè)置為 1,服務(wù)端必須存儲(chǔ)這個(gè)應(yīng)用消息和它的服務(wù)質(zhì)量等級(jí)(QoS),以便它可以被分發(fā)給未來的主題名匹配的訂閱者 。一個(gè)新的訂閱建立時(shí),對(duì)每個(gè)匹配的主題名,如果存在最近保留的消息,它必須被發(fā)送給這個(gè)訂閱者。如果服務(wù)端收到一條保留(RETAIN)標(biāo)志為1的Q消息,它必須丟棄之前為那個(gè)主題保留的任何消息,并將這個(gè)新的消息當(dāng)作那個(gè)主題的新保留消息。
保留標(biāo)志為 1 且有效載荷為零字節(jié)的 Publish 報(bào)文會(huì)被服務(wù)端當(dāng)作正常消息處理,它會(huì)被發(fā)送給訂閱主題匹配的客戶端。此外,同一個(gè)主題下任何現(xiàn)存的保留消息必須被移除,因此這個(gè)主題之后的任何訂閱者都不會(huì)收到保留消息。
服務(wù)端發(fā)送 Publish 報(bào)文給客戶端時(shí),如果消息是作為客戶端一個(gè)新訂閱的結(jié)果發(fā)送,它必須將報(bào)文的保留標(biāo)志設(shè)為 1。當(dāng)一個(gè) Publish 報(bào)文發(fā)送給客戶端是因?yàn)槠ヅ湟粋€(gè)已建立的訂閱時(shí),服務(wù)端必須將保留標(biāo)志設(shè)為 0,不管它收到的這個(gè)消息中保留標(biāo)志的值是多少。
如果客戶端發(fā)給服務(wù)端的 Publish 報(bào)文的保留標(biāo)志位 0,服務(wù)端不能存儲(chǔ)這個(gè)消息也不能移除或替換任何現(xiàn)存的保留消息。
Payload
有效載荷包含將被發(fā)布的應(yīng)用消息。數(shù)據(jù)的內(nèi)容和格式是應(yīng)用特定的,可以發(fā)送圖像,任何編碼的文本,加密的數(shù)據(jù)以及幾乎所有二進(jìn)制數(shù)據(jù)。
?
?
參考:https://www.emqx.com/zh/blog/how-to-use-mqtt-packet-to-implement-publishing-and-subscribing-functions
本文摘自 :https://www.cnblogs.com/