物聯網之MQTT3.1.1和MQTT5協議 (3) CONNACK 報文

前言

本篇博文介紹,MQTT的另一個報文,即CONNECK,由服務端發送。

CONNACK – 確認連接請求

CONNACK報文由服務端所發送,作爲對來自客戶端的CONNECT報文的響應。

在MQTT5中,服務端在發送任何除AUTH以外的報文之前必須先發送包含原因碼爲0x00(成功)的CONNACK報文。服務端在一次網絡連接中不能發送多個CONNACK報文

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

固定報頭

圖例 CONNACK 報文固定報頭
在這裏插入圖片描述

剩餘長度字段

用變長字節整數來編碼,表示可變報頭的長度。

可變報頭

在MQTT5中,CONNACK報文的可變報頭按順序包含以下字段:連接確認標誌(Connect Acknowledge Flags),連接原因碼(Reason Code),屬性(Properties)。

MQTT3.1.1中沒有屬性

在這裏插入圖片描述

MQTT5則無此示例圖

連接確認標誌

第1個字節是 連接確認標誌,位7-1是保留位且必須設置爲0

第0 (SP1SP^1)位 是當前會話(Session Present)標誌。

當前會話

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

【MQTT3.1.1】

如果服務端收到清理會話(CleanSession)標誌爲1的連接,除了將CONNACK報文中的返回碼設置爲0之外,還必須將CONNACK報文中的當前會話設置(Session Present)標誌爲0

==如果服務端收到一個Clean Session爲0的連接,當前會話標誌的值取決於服務端是否已經保存了ClientId對應客戶端的會話狀態。如果服務端已經保存了會話狀態,它必須將CONNACK報文中的當前會話標誌設置爲1 。如果服務端沒有已保存的會話狀態,它必須將CONNACK報文中的當前會話設置爲0。還需要將CONNACK報文中的返回碼設置爲0 ==。

當前會話標誌使服務端和客戶端在是否有已存儲的會話狀態上保持一致。

一旦完成了會話的初始化設置,已經保存會話狀態的客戶端將期望服務端維持它存儲的會話狀態。如果客戶端從服務端收到的當前的值與預期的不同,客戶端可以選擇繼續這個會話或者斷開連接。客戶端可以丟棄客戶端和服務端之間的會話狀態,方法是,斷開連接,將清理會話標誌設置爲1,再次連接,然後再次斷開連接。

如果服務端發送了一個包含非零返回碼的CONNACK報文,它必須將當前會話標誌設置爲0

【MQTT 5】

會話存在(Session Present)標誌通知客戶端,服務端是否正在使用此客戶標識符之前連接的會話狀態(Session State)。會話存在標誌使服務端和客戶端在是否有已存儲的會話狀態上保持一致。

如果服務端接受一個新開始(Clean Start)爲1的連接,服務端在CONNACK報文中除了把原因碼設置爲0x00(成功)之外,還必須把會話存在標誌設置爲0

如果服務端接受一個新開始(Clean Start)爲0的連接,並且服務端已經保存了此客戶標識符(ClientID)的會話狀態(Session State),服務端在CONNACK報文中必須把會話存在標誌設置爲1。否則,服務端必須把會話存在標誌設置爲0。無論如何,服務端在CONNACK報文中必須把原因碼設置爲0x00(成功)

如果客戶端從服務端接收到的會話存在標誌值與預期的不同,客戶端做如下處理:

  • 如果客戶端沒有保存的會話狀態,但收到會話存在標誌爲1,客戶端必須關閉網絡連接
  • 如果希望重新開始一個新的會話,客戶端可以使用新開始(Clean Start)爲1並重新連接服務端。
  • 如果客戶端保存了會話狀態,但收到的會話存在標誌爲0,客戶端若要繼續此網絡連接,它必須丟棄其保存的會話狀態
  • 如果服務端發送的CONNACK報文中原因碼非0,它必須把會話存在標誌設置爲0

連接返回碼(MQTT 3)

位置:可變報頭的第2個字節。

連接返回碼字段使用一個字節的無符號值,在 下表 中列出。如果服務端收到一個合法的CONNECT報文,但出於某些原因無法處理它,服務端應該嘗試發送一個包含非零返回碼(表格中的某一個)的CONNACK報文。如果服務端發送了一個包含非零返回碼的CONNACK報文,那麼它必須關閉網絡連接

MQTT3.1.1的連接返回碼和MQTT5的原因碼有些類似,MQTT5 的原因碼大多在0x80及以上。

在這裏插入圖片描述

如果認爲上表中的所有連接返回碼都不太合適,那麼服務端必須關閉網絡連接,不需要發送CONNACK報文。

連接原因碼(MQTT 5)

位置:可變報頭的第2個字節。

可變報頭中第2個字節是連接原因碼(Reason Code)。

連接原因代碼的值如下所示。 如果服務器接收到格式正確的CONNECT數據包,但是服務器無法完成連接,則服務器可以發送一個CONNACK數據包,其中包含來自該表的適當的Connect Reason代碼。 如果服務器發送的CONNACK數據包包含原因碼爲128或更高,則必須關閉網絡連接。
在這裏插入圖片描述

服務端發送的CONNACK報文必須設置一種原因碼

原因碼0x80(未指明的錯誤)可以被用作:服務器知道失敗的原因但是並不希望透露給客戶端,或者沒有其他適用的原因碼

出於安全考慮,發現CONNECT出錯時服務端可以選擇不發送CONNACK報文而關閉網絡連接。例如,在公網中向未被授權的網絡連接告知自身MQTT服務端身份並不明智。

CONNACK屬性(MQTT 5)

屬性長度

CONNACK報文可變報頭中的屬性長度,編碼爲變長字節整數

會話過期間隔

17 (0x11)Byte,會話過期間隔(Session Expiry Interval)標識符。

跟隨其後的是用四字節整數表示的以秒爲單位的會話過期間隔(Session Expiry Interval)。包含多個會話過期間隔(Session Expiry Interval)將造成協議錯誤(Protocol Error)。

如果會話過期間隔(Session Expiry Interval)值未指定,則使用CONNECT報文中指定的會話過期時間間隔。服務端使用此屬性通知客戶端它使用的會話過期時間間隔與客戶端在CONNECT中發送的值不同。

接收最大值

33 (0x21)Byte,接收最大值(Receive Maximum)描述符。
跟隨其後的是由雙字節整數表示的最大接收值。包含多個接收最大值或接收最大值爲0將造成協議錯誤(Protocol Error)。

服務端使用此值限制服務端願意爲該客戶端同時處理的QoS爲1和QoS爲2的發佈消息最大數量。沒有機制可以限制客戶端試圖發送的QoS爲0的發佈消息。

如果沒有設置最大接收值,將使用默認值65535。

最大服務質量

36 (0x24)Byte,最大服務質量(Maximum QoS)標識符。

跟隨其後的是用一個字節表示的0或1。包含多個最大服務質量(Maximum QoS)或最大服務質量既不爲0也不爲1將造成協議錯誤。如果沒有設置最大服務質量,客戶端可使用最大QoS爲2。

如果服務端不支持Qos爲1或2的PUBLISH報文,服務端必須在CONNACK報文中發送最大服務質量以指定其支持的最大QoS值。即使不支持QoS爲1或2的PUBLISH報文,服務端也必須接受請求QoS爲0、1或2的SUBSCRIBE報文

如果從服務端接收到了最大QoS等級,則客戶端不能發送超過最大QoS等級所指定的QoS等級的PUBLISH報文。服務端接收到超過其指定的最大服務質量的PUBLISH報文將造成協議錯誤(Protocol Error)。這種情況下應使用包含原因碼爲0x9B(不支持的QoS等級)的DISCONNECT報文進行處理。

如果服務端收到包含遺囑的QoS超過服務端處理能力的CONNECT報文,服務端必須拒絕此連接。服務端應該使用包含原因碼爲0x9B(不支持的QoS等級)的CONNACK報文進行錯誤處理,隨後必須關閉網絡連接

客戶端不必支持QoS爲1和2的PUBLISH報文。客戶端只需將其發送的任何SUBSCRIBE報文中的QoS字段限制在其支持的最大服務質量以內即可。

保留可用

37 (0x25)Byte,保留可用(Retain Available)標識符。

跟隨其後的是一個單字節字段,用來聲明服務端是否支持保留消息。值爲0表示不支持保留消息,爲1表示支持保留消息。如果沒有設置保留可用字段,表示支持保留消息。包含多個保留可用字段或保留可用字段值不爲0也不爲1將造成協議錯誤(Protocol Error)。

如果服務端收到一個包含保留標誌位1的遺囑消息的CONNECT報文且服務端不支持保留消息,服務端必須拒絕此連接請求,且應該發送包含原因碼爲0x9A(不支持保留)的CONNACK報文,隨後必須關閉網絡連接

從服務端接收到的保留可用標誌爲0時,客戶端不能發送保留標誌設置爲1的PUBLISH報文。如果服務端收到這種PUBLISH報文,將造成協議錯誤(Protocol Error),此時服務端應該發送包含原因碼爲0x9A(不支持保留)的DISCONNECT報文。

最大報文長度

39 (0x27)Byte,最大報文長度(Maximum Packet Size)標識符。

跟隨其後的是由四字節整數表示的服務端願意接收的最大報文長度(Maximum Packet Size)。如果沒有設置最大報文長度,則按照協議由固定報頭中的剩餘長度可編碼最大值和協議報頭對數據包的大小做限制。

包含多個最大報文長度(Maximum Packet Size),或最大報文長度爲0將造成協議錯誤(Protocol Error)。

最大報文長度是MQTT控制報文的總長度。服務端使用最大報文長度通知客戶端其所能處理的單個報文長度限制。

客戶端不能發送超過最大報文長度(Maximum Packet Size)的報文給服務端。收到長度超過限制的報文將導致協議錯誤,此時服務端應該發送包含原因碼0x95(報文過長)的DISCONNECT報文給客戶端。

分配客戶標識符

18 (0x12)Byte,分配客戶標識符(Assigned Client Identifier)標識符。

跟隨其後的是UTF-8編碼的分配客戶標識符(Assigned Client Identifier)字符串。包含多個分配客戶標識符將造成協議錯誤(Protocol Error)。 服務端分配客戶標識符的原因是CONNECT報文中的客戶標識符長度爲0。

如果客戶端使用長度爲0的客戶標識符(ClientID),服務端必須回覆包含分配客戶標識符(Assigned Client Identifier)的CONNACK報文。分配客戶標識符必須是沒有被服務端的其他會話所使用的新客戶標識符

主題別名最大值

34 (0x22)Byte,主題別名最大值(Topic Alias Maximum)標識符。

跟隨其後的是用雙字節整數表示的主題別名最大值(Topic Alias Maximum)。包含多個主題別名最大值(Topic Alias Maximum)將造成協議錯誤(Protocol Error)。沒有設置主題別名最大值屬性的情況下,主題別名最大值默認爲零。

此值指示了服務端能夠接收的來自客戶端的主題別名(Topic Alias)最大值。服務端使用此值來限制本次連接可以擁有的主題別名的值。客戶端在一個PUBLISH報文中發送的主題別名值不能超過服務端設置的主題別名最大值(Topic Alias Maximum)。值爲0表示本次連接服務端不接受任何主題別名(Topic Alias)。如果主題別名最大值(Topic Alias)沒有設置,或者設置爲0,則客戶端不能向此服務端發送任何主題別名(Topic Alias)

原因字符串

31 (0x1F)Byte,原因字符串(Reason String)標識符。

跟隨其後的是UTF-8編碼的字符串,表示此次響應相關的原因。此原因字符串(Reason String)是爲診斷而設計的可讀字符串,不應該被客戶端所解析。

服務端使用此值向客戶端提供附加信息。如果加上原因字符串之後的CONNACK報文長度超出了客戶端指定的最大報文長度,則服務端不能發送此原因字符串。包含多個原因字符串將造成協議錯誤(Protocol Error)。

客戶端對原因字符串的恰當使用包括:拋出異常時使用此字符串,或者將此字符串寫入日誌。

用戶屬性

38 (0x26)Byte,用戶屬性(User Property)標識符。 跟隨其後的是UTF-8字符串對。此屬性可用於向客戶端提供包括診斷信息在內的附加信息。如果加上用戶屬性之後的CONNACK報文長度超出了客戶端指定的最大報文長度,則服務端不能發送此屬性。用戶屬性(User Property)允許出現多次,以表示多個名字/值對,且相同的名字可以多次出現。

用戶屬性的內容和意義不做定義。CONNACK報文的接收端可以選擇忽略此屬性。

通配符訂閱可用

40 (0x28)Byte,通配符訂閱可用(Wildcard Subscription Available)標識符。

跟隨其後的是一個單字節字段,用來聲明服務器是否支持通配符訂閱(Wildcard Subscriptions)。值爲0 表示不支持通配符訂閱,值爲1表示支持通配符訂閱。如果沒有設置此值,則表示支持通配符訂閱。包含多個通配符訂閱可用屬性,或通配符訂閱可用屬性值不爲0也不爲1將造成協議錯誤(Protocol Error)。

如果服務端在不支持通配符訂閱(Wildcard Subscription)的情況下收到了包含通配符訂閱的SUBSCRIBE 報文,將造成協議錯誤(Protocol Error)。此時服務端將發送包含原因碼爲0xA2(通配符訂閱不支持)的DISCONNECT報文。

服務端在支持通配符訂閱的情況下仍然可以拒絕特定的包含通配符訂閱的訂閱請求。這種情況下,服務端可以發送一個包含原因碼爲0xA2(通配符訂閱不支持)的SUBACK報文。

訂閱標識符可用

41 (0x29)Byte,訂閱標識符可用(Subscription Identifier Available)標識符。

跟隨其後的是一個單字節字段,用來聲明服務端是否支持訂閱標識符(Subscription Identifiers)。值爲0表示不支持訂閱標識符,值爲1表示支持訂閱標識符。如果沒有設置此值,則表示支持訂閱標識符。包含多個訂閱標識符可用屬性,或訂閱標識符可用屬性值不爲0也不爲1將造成協議錯誤(Protocol Error)。

如果服務端在不支持訂閱標識符(Subscription Identifier)的情況下收到了包含訂閱標識符的SUBSCRIBE 報文,將造成協議錯誤(Protocol Error)。此時服務端將發送包含原因碼爲0xA1(訂閱標識符不支持)的DISCONNECT報文。

共享訂閱可用

42 (0x2A)Byte,共享訂閱可用(Shared Subscription Available)標識符。

跟隨其後的是一個單字節字段,用來聲明服務端是否支持共享訂閱(Shared Subscription)。值爲0表示不支持共享訂閱,值爲1表示支持共享訂閱。如果沒有設置此值,則表示支持共享訂閱。包含多個共享訂閱可用(Shared Subscription Available),或共享訂閱可用屬性值不爲0也不爲1將造成協議錯誤(Protocol Error)。

如果服務端在不支持共享訂閱(Shared Subscription)的情況下收到了包含共享訂閱的SUBSCRIBE報文,將造成協議錯誤(Protocol Error)。此時服務端將發送包含原因碼爲0x9E(共享訂閱不支持)的DISCONNECT報文。

服務端保活

19 (0x13)Byte,服務端保活(Server Keep Alive)標識符。

跟隨其後的是由服務端分配的雙字節整數表示的保活(Keep Alive)時間。如果服務端發送了服務端保活(Server Keep Alive)屬性,客戶端必須使用此值代替其在CONNECT報文中發送的保活時間值如果服務端沒有發送服務端保活屬性,服務端必須使用客戶端在CONNECT報文中設置的保活時間值。包含多個服務端保活屬性將造成協議錯誤(Protocol Error)。

服務器保持保活的主要用途是使服務器通知客戶端,它將比客戶端指定的保活狀態更早地斷開客戶端的連接。

響應信息

26 (0x1A)Byte,響應信息(Response Information)標識符。
跟隨其後的是一個以UTF-8編碼的字符串,作爲創建響應主題(Response Topic)的基本信息。關於客戶端如何根據響應信息(Response Information)創建響應主題不在MQTT規範中的定義範圍內。包含多個響應信息將造成協議錯誤(Protocol Error)。

如果客戶端發送的請求響應信息(Request Response Information)值爲1,則服務端在CONNACK報文中發送響應信息(Response Information)爲可選項。

響應信息通常被用來傳遞主題訂閱樹的一個全局唯一分支,此分支至少在該客戶端的會話生命週期內爲該客戶端所保留。請求客戶端和響應客戶端的授權需要使用它,所以它通常不能僅僅是一個隨機字符串。一般把此分支作爲特定客戶端的訂閱樹根節點。通常此信息需要正確配置,以使得服務器能返回信息。使用此機制時,具體的信息一般由服務端來進行統一配置,而非由各個客戶端自己配置。

服務端參考列表

28 (0x1C)Byte,服務端參考列表(Server Reference)標識符。
跟隨其後的是一個以UTF-8編碼的字符串,可以被客戶端用來標識其他可用的服務端。包含多個服務端參考(Server Reference)將造成協議錯誤(Protocol Error)。

服務端在包含了原因碼爲0x9C(使用其他服務端)或0x9D(服務端已移動)的CONNACK報文或DISCONNECT報文中設置服務端參考列表。

認證方法

21 (0x15)Byte,認證方法(Authentication Method)標識符。
跟隨其後的是一個以UTF-8編碼的字符串,包含了認證方法(Authentication Method)名。包含多個認證方法將造成協議錯誤(Protocol Error)。

認證數據

22 (0x16)Byte,認證數據(Authentication Data)標識符。
跟隨其後的是包含認證數據(Authentication Data)的二進制數據。此數據的內容由認證方法和已交換的認證數據狀態定義。包含多個認證數據將造成協議錯誤(Protocol Error)。

CONNACK載荷

CONNACK報文沒有有效載荷。

總結

CONNACK相對簡單,下一次便是PUBLISH報文的介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章