Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

穆書偉發表於2019-03-02
Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

前言

誕生及優勢

MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,現為Cirrus Link)於1999年開發,用於監測穿越沙漠的石油管道。目標是擁有一個頻寬有效且使用很少電池電量的協議,因為這些裝置是通過衛星鏈路連線的,當時這種裝置非常昂貴。
與HTTP及其請求/響應範例相比,該協議使用釋出/訂閱體系結構。釋出/訂閱是事件驅動的,可以將訊息推送到客戶端。中央通訊點是MQTT代理,它負責排程傳送者和合法接收者之間的所有訊息。向代理髮布訊息的每個客戶端都在訊息中包含一個主題。主題是代理的路由資訊​。每個想要接收訊息的客戶端都訂閱某個主題,並且代理將具有匹配主題的所有訊息傳遞給客戶端。因此,客戶不必彼此瞭解,他們只通過主題進行通訊。該架構支援高度可擴充套件的解決方案,而不依賴於資料生產者和資料使用者。

Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

釋出/訂閱架構

與HTTP的區別在於客戶端不必提取所需的資訊,但是在有新內容的情況下,代理會將資訊推送到客戶端。因此,每個MQTT客戶端都與代理具有永久開啟的TCP連線。如果此連線在任何情況下中斷,MQTT代理可以緩衝所有訊息,並在它重新聯機時將它們傳送到客戶端。
如前所述,MQTT中用於分派訊息的核心概念是主題。主題是一個簡單的字串,可以有更多的層次結構級別,用斜槓分隔。用於傳送起居室的溫度資料的示例主題可以是房屋/起居室/溫度。一方面,客戶端可以訂閱確切的主題,或者另一方面使用萬用字元。對房屋/ + /溫度的訂閱將導致所有訊息傳送到先前提到的主題房屋/起居室/溫度以及在起居室的地方具有任意值的任何主題,例如房屋/廚房/溫度。加號是單級萬用字元,只允許一個層次結構的任意值。如果您需要訂閱多個級別,例如訂閱整個子樹,還有一個多級萬用字元)。它允許訂閱所有底層層次結構級別。比如房子/#訂閱以house開頭的所有主題。

實用人群

以下內容需要你對照著MQTT協議內容仔細推敲

推薦資源:

MQTT協議中文版: mcxiaoke.gitbooks.io/mqtt-cn/con…

MQTT Version 3.1.1: docs.oasis-open.org/mqtt/mqtt/v…

MQTT控制報文格式

MQTT控制報文結構

結構 備註
Fixed header 固定報頭,所有控制報文都包含
Variable header 可變報頭,部分控制報文包含
Payload 有效載荷,部分控制報文包含

固定報頭 Fixed header

+-----+-----+-----+-----+-----+------+------+------+-------+
|     |     |     |     |     |      |      |      |       |
| Bit |  7  |  6  |  5  |  4  |  3   |  2   |  1   |  0    |
+-----------+-----+-----+------------+------+------+-------+
|     |                       |                            |
|byte1|MQTT ControlPacket type|          Flags             |
+----------------------------------------------------------+
|     |                                                    |
|byte2|          Remaining Length                          |
+----------------------------------------------------------+
複製程式碼

控制報文型別(MQTT Control Packet type)

名字 報文流動方向 描述
Reserved 0 禁止 保留
CONNECT 1 客戶端到服務端 客戶端請求連線服務端
CONNACK 2 服務端到客戶端 連線報文確認
PUBLISH 3 兩個方向都允許 釋出訊息
PUBACK 4 兩個方向都允許 QoS 1訊息釋出收到確認
PUBREC 5 兩個方向都允許 釋出收到(保證交付第一步)
PUBREL 6 兩個方向都允許 釋出釋放(保證交付第二步)
PUBCOMP 7 兩個方向都允許 QoS 2訊息釋出完成(保證互動第三步)
SUBSCRIBE 8 客戶端到服務端 客戶端訂閱請求
SUBACK 9 服務端到客戶端 訂閱請求報文確認
UNSUBSCRIBE 10 客戶端到服務端 客戶端取消訂閱請求
UNSUBACK 11 服務端到客戶端 取消訂閱報文確認
PINGREQ 12 客戶端到服務端 心跳請求
PINGRESP 13 服務端到客戶端 心跳響應
DISCONNECT 14 客戶端到服務端 客戶端斷開連線
Reserved 15 禁止 保留

標誌(Flags)

控制報文 固定報頭標誌 Bit 3 Bit 2 Bit 1 Bit 0
CONNECT Reserved 0 0 0 0
CONNACK Reserved 0 0 0 0
PUBLISH Used in MQTT 3.1.1 DUP1 QoS2 QoS2 RETAIN3
PUBACK Reserved 0 0 0 0
PUBREC Reserved 0 0 0 0
PUBREL Reserved 0 0 1 0
PUBCOMP Reserved 0 0 0 0
SUBSCRIBE Reserved 0 0 1 0
SUBACK Reserved 0 0 0 0
UNSUBSCRIBE Reserved 0 0 1 0
UNSUBACK Reserved 0 0 0 0
PINGREQ Reserved 0 0 0 0
PINGRESP Reserved 0 0 0 0
DISCONNECT Reserved 0 0 0 0
Bit3 Bit2 Bit1 Bit0
DUP Qos Qos RETAIN
  • DUP =控制報文的重複分發標誌
  • QoS = PUBLISH報文的服務質量等級
  • RETAIN = PUBLISH報文的保留標誌

備註:

服務質量等級Qos:**位置:**第1個位元組,第2-1位。這個欄位表示應用訊息分發的服務質量等級保證。

QoS值 Bit 2 Bit 1 描述
0 0 0 最多分發一次
1 0 1 至少分發一次
2 1 0 只分發一次
1 1 保留位

剩餘長度(Remaining Length)

**位置:**從第2個位元組開始。

剩餘長度(Remaining Length)表示當前報文剩餘部分的位元組數,包括可變報頭和負載的資料。剩餘長度不包括用於編碼剩餘長度欄位本身的位元組數。

可變報頭(Variable header)

某些MQTT控制報文包含一個可變報頭部分。它在固定報頭和負載之間。可變報頭的內容根據報文型別的不同而不同。可變報頭的報文識別符號(Packet Identifier)欄位存在於在多個型別的報文裡。這個在後續的MQTT各個控制報文中進行手撕

有效載荷(Payload)

某些MQTT控制報文在報文的最後部分包含一個有效載荷,對於PUBLISH來說有效載荷就是應用訊息。

包含有效載荷的控制報文Control Packets that contain a Payload

控制報文 有效載荷
CONNECT 需要
CONNACK 不需要
PUBLISH 可選
PUBACK 不需要
PUBREC 不需要
PUBREL 不需要
PUBCOMP 不需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
UNSUBACK 不需要
PINGREQ 不需要
PINGRESP 不需要
DISCONNECT 不需要
Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

MQTT控制報文

CONNECT – 連線服務端

客戶端到服務端的網路連線建立後,客戶端傳送給服務端的第一個報文必須是CONNECT報文 。

在一個網路連線上,客戶端只能傳送一次CONNECT報文。服務端必須將客戶端傳送的第二個CONNECT報文當作協議違規處理並斷開客戶端的連線。

有效載荷包含一個或多個編碼的欄位。包括客戶端的唯一識別符號,Will主題,Will訊息,使用者名稱和密碼。除了客戶端標識之外,其它的欄位都是可選的,基於標誌位來決定可變報頭中是否需要包含這些欄位。

可變報頭

CONNECT報文的可變報頭按下列次序包含四個欄位:協議名(Protocol Name),協議級別(Protocol Level),連線標誌(Connect Flags)和保持連線(Keep Alive)。

協議名(Protocol Name)

協議名是表示協議名 MQTT 的UTF-8編碼的字串。MQTT規範的後續版本不會改變這個字串的偏移和長度。

如果協議名不正確服務端可以斷開客戶端的連線,也可以按照某些其它規範繼續處理CONNECT報文。對於後一種情況,按照本規範,服務端不能繼續處理CONNECT報文

協議級別(Protocol Level)

客戶端用8位的無符號值表示協議的修訂版本。對於3.1.1版協議,協議級別欄位的值是4(0x04)。

如果發現不支援的協議級別,服務端必須給傳送一個返回碼為0x01(不支援的協議級別)的CONNACK報文響應CONNECT報文,然後斷開客戶端的連線 。

連線標誌(Connect Flags)

連線標誌位元組包含一些用於指定MQTT連線行為的引數。它還指出有效載荷中的欄位是否存在

+-------+---------+----------+--------+------+-------+-------+--------+--------+
|       |         |          |        |      |       |       |        |        |
|  Bit  |    7    |    6     |   5    |  4   |  3    |   2   |   1    |   0    |
+--------------------------------------------+---------------------------------+
|       |User Name|Password  | Will   |              | Will  | Clean  |        |
|       | Flag    | Flag     | Retain |  Will Qos    | Flag  |Session |Reser^ed|
+--------------------------------------------+---------------------------------+
|       |         |          |        |      |       |       |        |        |
| byte8 |    X    |    X     |    X   |   X  |   X   |   X   |   X    |   0    |
+-------+---------+----------+--------+------+-------+-------+--------+--------+

複製程式碼

服務端必須驗證CONNECT控制報文的保留標誌位(第0位)是否為0,如果不為0必須斷開客戶端連線 。

清理會話 Clean Session

**位置:**連線標誌位元組的第1位

這個二進位制位指定了會話狀態的處理方式。

客戶端和服務端可以儲存會話狀態,以支援跨網路連線的可靠訊息傳輸。這個標誌位用於控制會話狀態的生存時間。

遺囑標誌 Will Flag

**位置:**連線標誌的第2位。

遺囑標誌(Will Flag)被設定為1,表示如果連線請求被接受了,遺囑(Will Message)訊息必須被儲存在服務端並且與這個網路連線關聯。之後網路連線關閉時,服務端必須釋出這個遺囑訊息,除非服務端收到DISCONNECT報文時刪除了這個遺囑訊息

遺囑QoS Will QoS

**位置:**連線標誌的第4和第3位。

這兩位用於指定釋出遺囑訊息時使用的服務質量等級。

遺囑保留 Will Retain

**位置:**連線標誌的第5位。

如果遺囑訊息被髮布時需要保留,需要指定這一位的值。

使用者名稱標誌 User Name Flag

**位置:**連線標誌的第7位。

如果使用者名稱(User Name)標誌被設定為0,有效載荷中不能包含使用者名稱欄位 。

如果使用者名稱(User Name)標誌被設定為1,有效載荷中必須包含使用者名稱欄位 。

密碼標誌 Password Flag

**位置:**連線標誌的第6位。

如果密碼(Password)標誌被設定為0,有效載荷中不能包含密碼欄位 。

如果密碼(Password)標誌被設定為1,有效載荷中必須包含密碼欄位 。

如果使用者名稱標誌被設定為0,密碼標誌也必須設定為0 。

保持連線 Keep Alive

保持連線(Keep Alive)是一個以秒為單位的時間間隔,表示為一個16位的字,它是指在客戶端傳輸完成一個控制報文的時刻到傳送下一個報文的時刻,兩者之間允許空閒的最大時間間隔。

客戶端負責保證控制報文傳送的時間間隔不超過保持連線的值。如果沒有任何其它的控制報文可以傳送,客戶端必須傳送一個PINGREQ報文 。

有效載荷

CONNECT報文的有效載荷(payload)包含一個或多個以長度為字首的欄位,可變報頭中的標誌決定是否包含這些欄位。如果包含的話,必須按這個順序出現:客戶端識別符號,遺囑主題,遺囑訊息,使用者名稱,密碼 。

響應Response

  1. 網路連線建立後,如果服務端在合理的時間內沒有收到CONNECT報文,服務端應該關閉這個連線。
  2. 服務端必須按照3.1節的要求驗證CONNECT報文,如果報文不符合規範,服務端不傳送CONNACK報文直接關閉網路連線 [MQTT-3.1.4-1]。
  3. 服務端可以檢查CONNECT報文的內容是不是滿足任何進一步的限制,可以執行身份驗證和授權檢查。如果任何一項檢查沒通過,按照3.2節的描述,它應該傳送一個適當的、返回碼非零的CONNACK響應,並且必須關閉這個網路連線。

CONNACK – 確認連線請求

服務端傳送CONNACK報文響應從客戶端收到的CONNECT報文。服務端傳送給客戶端的第一個報文必須是CONNACK。

如果客戶端在合理的時間內沒有收到服務端的CONNACK報文,客戶端應該關閉網路連線。合理 的時間取決於應用的型別和通訊基礎設施。

剩餘長度欄位

表示可變報頭的長度。對於CONNACK報文這個值等於2。

可變報頭

連線確認標誌 Connect Acknowledge Flags

第1個位元組是 連線確認標誌,位7-1是保留位且必須設定為0。 第0 (SP)位 是當前會話(Session Present)標誌。

當前會話 Session Present

**位置:**連線確認標誌的第0位。

連線返回碼 Connect Return code

**位置:**可變報頭的第2個位元組。

連線返回碼欄位使用一個位元組的無符號值。如果服務端收到一個合法的CONNECT報文,但出於某些原因無法處理它,服務端應該嘗試傳送一個包含非零返回碼(表格中的某一個)的CONNACK報文。如果服務端傳送了一個包含非零返回碼的CONNACK報文,那麼它必須關閉網路連線 。

表格 3.1 –連線返回碼的值
返回碼響應 描述
0 0x00連線已接受 連線已被服務端接受
1 0x01連線已拒絕,不支援的協議版本 服務端不支援客戶端請求的MQTT協議級別
2 0x02連線已拒絕,不合格的客戶端識別符號 客戶端識別符號是正確的UTF-8編碼,但服務端不允許使用
3 0x03連線已拒絕,服務端不可用 網路連線已建立,但MQTT服務不可用
4 0x04連線已拒絕,無效的使用者名稱或密碼 使用者名稱或密碼的資料格式無效
5 0x05連線已拒絕,未授權 客戶端未被授權連線到此伺服器
6-255 保留

有效載荷

CONNACK報文沒有有效載荷。

Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

PUBLISH – 釋出訊息

PUBLISH控制報文是指從客戶端向服務端或者服務端向客戶端傳輸一個應用訊息。

固定報頭

  • DUP =控制報文的重複分發標誌
  • QoS = PUBLISH報文的服務質量等級
  • RETAIN = PUBLISH報文的保留標誌

可變報頭

可變報頭按順序包含主題名和報文識別符號。

主題名 Topic Name

主題名(Topic Name)用於識別有效載荷資料應該被髮布到哪一個資訊通道。

主題名必須是PUBLISH報文可變報頭的第一個欄位。它必須是 1.5.3節定義的UTF-8編碼的字串。

PUBLISH報文中的主題名不能包含萬用字元 。

服務端傳送給訂閱客戶端的PUBLISH報文的主題名必須匹配該訂閱的主題過濾器(根據 4.7節定義的匹配過程)。

報文識別符號 Packet Identifier

只有當QoS等級是1或2時,報文識別符號(Packet Identifier)欄位才能出現在PUBLISH報文中。2.3.1節提供了有關報文識別符號的更多資訊。

有效載荷

有效載荷包含將被髮布的應用訊息。

資料的內容和格式是應用特定的。有效載荷的長度這樣計算:用固定報頭中的剩餘長度欄位的值減去可變報頭的長度。包含零長度有效載荷的PUBLISH報文是合法的。

響應

PUBLISH報文的接收者必須按照根據PUBLISH報文中的QoS等級傳送響應。

服務質量等級 預期響應
QoS 0 無響應
QoS 1 PUBACK報文
QoS 2 PUBREC報文

PUBACK –釋出確認

PUBACK報文是對QoS 1等級的PUBLISH報文的響應。

剩餘長度欄位

表示可變報頭的長度。對PUBACK報文這個值等於2.

可變報頭

包含等待確認的PUBLISH報文的報文識別符號。

有效載荷

PUBACK報文沒有有效載荷。

PUBREC – 釋出收到(QoS 2,第一步)

PUBREC報文是對QoS等級2的PUBLISH報文的響應。它是QoS 2等級協議交換的第二個報文。

剩餘長度欄位

表示可變報頭的長度。對PUBREC報文它的值等於2。

可變報頭

可變報頭包含等待確認的PUBLISH報文的報文識別符號。

有效載荷

PUBREC報文沒有有效載荷。

Netty實現

 MqttMessage pubRecMessage = MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.PUBREC, false, MqttQoS.AT_MOST_ONCE, false, 2),
                MqttMessageIdVariableHeader.from(variableHeader.messageId()),
                null);
複製程式碼

PUBREL – 釋出釋放(QoS 2,第二步)

PUBREL報文是對PUBREC報文的響應。它是QoS 2等級協議交換的第三個報文。

PUBREL控制報文固定報頭的第3,2,1,0位是保留位,必須被設定為0,0,1,0。服務端必須將其它的任何值都當做是不合法的並關閉網路連線 。

剩餘長度欄位

表示可變報頭的長度。對PUBREL報文這個值等於2.

可變報頭

可變報頭包含與等待確認的PUBREC報文相同的報文識別符號。

有效載荷

PUBREL報文沒有有效載荷。

Netty實現

MqttMessage pubRecMessage = MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.PUBREC, false, MqttQoS.AT_LEAST_ONCE, false, 2),
                MqttMessageIdVariableHeader.from(variableHeader.messageId()),
                null);
複製程式碼

PUBCOMP – 釋出完成(QoS 2,第三步)

PUBCOMP報文是對PUBREL報文的響應。它是QoS 2等級協議交換的第四個也是最後一個報文。

剩餘長度欄位

表示可變報頭的長度。對PUBCOMP報文這個值等於2。

可變報頭

可變報頭包含與等待確認的PUBREL報文相同的報文識別符號。

有效載荷

PUBCOMP報文沒有有效載荷。

Netty實現

 MqttMessage pubCompMessage = MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.PUBCOMP, false, MqttQoS.AT_MOST_ONCE, false, 2),
                MqttMessageIdVariableHeader.from(variableHeader.messageId()),
                null);
複製程式碼
Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

SUBSCRIBE – 訂閱主題

客戶端向服務端傳送SUBSCRIBE報文用於建立一個或多個訂閱。每個訂閱註冊客戶端關心的一個或多個主題。為了將應用訊息轉發給與那些訂閱匹配的主題,服務端傳送PUBLISH報文給客戶端。SUBSCRIBE報文也(為每個訂閱)指定了最大的QoS等級,服務端根據這個傳送應用訊息給客戶端。

剩餘長度欄位

等於可變報頭的長度(2位元組)加上有效載荷的長度。

可變報頭

可變報頭包含報文識別符號。

有效載荷

SUBSCRIBE報文的有效載荷包含了一個主題過濾器列表,它們表示客戶端想要訂閱的主題。

SUBSCRIBE報文有效載荷中的主題過濾器列表必須是1.5.3節定義的UTF-8字串 [MQTT-3.8.3-1]。

服務端應該支援包含萬用字元(4.7.1節定義的)的主題過濾器。如果服務端選擇不支援包含萬用字元的主題過濾器,必須拒絕任何包含萬用字元過濾器的訂閱請求 [MQTT-3.8.3-2]。

每一個過濾器後面跟著一個位元組,這個位元組被叫做 服務質量要求(Requested QoS)。它給出了服務端向客戶端傳送應用訊息所允許的最大QoS等級。

SUBSCRIBE報文的有效載荷必須包含至少一對主題過濾器 和 QoS等級欄位組合。沒有有效載荷的SUBSCRIBE報文是違反協議的 [MQTT-3.8.3-3]。有關錯誤處理的資訊請檢視4.8節。

請求的最大服務質量等級欄位編碼為一個位元組,它後面跟著UTF-8編碼的主題名,那些主題過濾器 /和QoS等級組合是連續地打包。

Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

當前版本的協議沒有用到服務質量要求(Requested QoS)位元組的高六位。如果有效載荷中的任何位是非零值,或者QoS不等於0,1或2,服務端必須認為SUBSCRIBE報文是不合法的並關閉網路連線 。

SUBACK – 訂閱確認

服務端傳送SUBACK報文給客戶端,用於確認它已收到並且正在處理SUBSCRIBE報文。

SUBACK報文包含一個返回碼清單,它們指定了SUBSCRIBE請求的每個訂閱被授予的最大QoS等級。

剩餘長度欄位

等於可變報頭的長度加上有效載荷的長度。

可變報頭

可變報頭包含等待確認的SUBSCRIBE報文的報文識別符號。

有效載荷

有效載荷包含一個返回碼清單。每個返回碼對應等待確認的SUBSCRIBE報文中的一個主題過濾器。返回碼的順序必須和SUBSCRIBE報文中主題過濾器的順序相同 。

Bit 7 6 5 4 3 2 1 0
返回碼
byte 1 X 0 0 0 0 0 X X

允許的返回碼值:

  • 0x00 – 最大QoS 0
  • 0x01 – 成功 – 最大QoS 1
  • 0x02 – 成功 – 最大 QoS 2
  • 0x80 – Failure 失敗

0x00, 0x01, 0x02, 0x80之外的SUBACK返回碼是保留的,不能使用。

UNSUBSCRIBE –取消訂閱

客戶端傳送UNSUBSCRIBE報文給服務端,用於取消訂閱主題。

UNSUBSCRIBE報文固定報頭的第3,2,1,0位是保留位且必須分別設定為0,0,1,0。

即:

  • DUP =控制報文的重複分發標誌 : false
  • QoS = PUBLISH報文的服務質量等級: Qos1(至少分發一次)
  • RETAIN = PUBLISH報文的保留標誌: false

服務端必須認為任何其它的值都是不合法的並關閉網路連線 。

剩餘長度欄位

等於可變報頭的長度加上有效載荷的長度。

可變報頭

有效載荷

UNSUBSCRIBE報文的有效載荷包含客戶端想要取消訂閱的主題過濾器列表。UNSUBSCRIBE報文中的主題過濾器必須是連續打包的。

UNSUBSCRIBE報文的有效載荷必須至少包含一個訊息過濾器。沒有有效載荷的UNSUBSCRIBE報文是違反協議的。

響應

UNSUBSCRIBE報文提供的主題過濾器(無論是否包含萬用字元)必須與服務端持有的這個客戶端的當前主題過濾器集合逐個字元比較。如果有任何過濾器完全匹配,那麼它(服務端)自己的訂閱將被刪除,否則不會有進一步的處理 。

如果服務端刪除了一個訂閱:

  • 必須停止分發任何新訊息給這個客戶端 。
  • 必須完成分發任何已經開始往客戶端傳送的QoS 1和QoS 2的訊息。
  • 可以繼續傳送任何現存的準備分發給客戶端的快取訊息。

服務端必須傳送UNSUBACK報文響應客戶端的UNSUBSCRIBE請求。UNSUBACK報文必須包含和UNSUBSCRIBE報文相同的報文識別符號 。即使沒有刪除任何主題訂閱,服務端也必須傳送一個UNSUBACK響應 。

如果服務端收到包含多個主題過濾器的UNSUBSCRIBE報文,它必須如同收到了一系列的多個UNSUBSCRIBE報文一樣處理那個報文,除了將它們的響應合併到一個單獨的UNSUBACK報文外。

UNSUBACK – 取消訂閱確認

服務端傳送UNSUBACK報文給客戶端用於確認收到UNSUBSCRIBE報文。

剩餘長度欄位

表示可變報頭的長度,對UNSUBACK報文這個值等於2。

可變報頭

可變報頭包含等待確認的UNSUBSCRIBE報文的報文識別符號。

有效載荷

UNSUBACK報文沒有有效載荷。

Netty實現

MqttUnsubAckMessage unsubAckMessage = (MqttUnsubAckMessage)MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.UNSUBACK, false, MqttQoS.AT_MOST_ONCE, false, 2),
 MqttMessageIdVariableHeader.from(msg.variableHeader().messageId()),
 null);
複製程式碼

PINGREQ – 心跳請求

客戶端傳送PINGREQ報文給服務端的。用於:

  1. 在沒有任何其它控制報文從客戶端發給服務的時,告知服務端客戶端還活著。
  2. 請求服務端傳送 響應確認它還活著。
  3. 使用網路以確認網路連線沒有斷開。

保持連線(Keep Alive)處理中用到這個報文。

可變報頭

PINGREQ報文沒有可變報頭。

有效載荷

PINGREQ報文沒有有效載荷。

響應

服務端必須傳送 PINGRESP報文響應客戶端的PINGREQ報文

Netty實現

 MqttMessage pingReqMessage = MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.PINGREQ, false,MqttQoS.AT_MOST_ONCE, false, 0),
                null,
                null);
複製程式碼

PINGRESP – 心跳響應

服務端傳送PINGRESP報文響應客戶端的PINGREQ報文。表示服務端還活著。保持連線(Keep Alive)處理中用到這個報文。

可變報頭

PINGRESP報文沒有可變報頭。

有效載荷

PINGRESP報文沒有有效載荷。

Netty實現

MqttMessage pingRespMessage = MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.PINGREQ, false,MqttQoS.AT_MOST_ONCE, false, 0),
                null,
                null);
複製程式碼
Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上

DISCONNECT –斷開連線

DISCONNECT報文是客戶端發給服務端的最後一個控制報文。表示客戶端正常斷開連線。

可變報頭

DISCONNECT報文沒有可變報頭。

有效載荷

DISCONNECT報文沒有有效載荷。

響應

客戶端傳送DISCONNECT報文之後:

  • 必須關閉網路連線 。
  • 不能通過那個網路連線再傳送任何控制報文 。

服務端在收到DISCONNECT報文時:

  • 必須丟棄任何與當前連線關聯的未釋出的遺囑訊息。
  • 應該關閉網路連線,如果客戶端 還沒有這麼做。

Netty實現

MqttMessage disConnectMessage = MqttMessageFactory.newMessage(
 new MqttFixedHeader(MqttMessageType.DISCONNECT, false,MqttQoS.AT_MOST_ONCE, false,0),
                null,
                null);
複製程式碼

其他

關於Netty實現高效能IOT伺服器(Groza)之手撕MQTT協議篇上詳解到這裡就結束了。

原創不易,如果感覺不錯,希望給個推薦!您的支援是我寫作的最大動力!

下文會帶大家推進Netty實現MQTT協議的IOT伺服器。

版權宣告:

作者:穆書偉

部落格園出處:www.cnblogs.com/sanshengshu…

github出處:github.com/sanshengshu…    

個人部落格出處:sanshengshui.github.io/

相關文章