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