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