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


 

 

 

前言

誕生及優勢

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

發布/訂閱架構

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

 

 

適用人群

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

推薦資源:

MQTT協議中文版: https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html

MQTT Version 3.1.1: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html

 

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 不需要

 

 

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報文沒有有效載荷。

 

 

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 pubRelMessage = 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);

 

 

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等級組合是連續地打包。

 

當前版本的協議沒有用到服務質量要求(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);

 

 

 

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服務器。

版權聲明:

作者:穆書偉

博客園出處:https://www.cnblogs.com/sanshengshui

github出處:https://github.com/sanshengshui    

個人博客出處:https://sanshengshui.github.io/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM