MQTT協議(二)

binger-csdn發表於2019-03-06

一.CONNECT報文

客戶端與伺服器建立網路連線後,客戶端傳送給伺服器的第一個報文必須是CONNECT報文。在一個連線上,客戶端只能傳送一次CONNECT報文,如果客戶端又再一次傳送了CONNECT報文,伺服器會把它當違規並斷開客戶端。有效載荷包含一個或多個的欄位,包括客戶端識別符號,Will主題,Will訊息,使用者名稱和密碼,這些除了客戶端識別符號之外,其它的欄位都是可選的,基於標誌位來決定可變報頭中是否需要包含這些欄位。

1、固定報頭

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

(1)  協議名(Protocol Name)

協議名是UTF-8編碼的字串。MQTT後續版本不會改變這個字串和長度。如果協議名不正確伺服器可以斷開客戶端的連線,也可以按照其它規範繼續處理這個CONNECT報文

(2)  協議級別(Protocol Level)

客戶端用8位的無符號值表示協議的版本。對於3.1.1協議,協議級別的值是4,如果發現不支援的協議級別,服務端必須給傳送一個返回碼為0x01(不支援該協議級別)的CONNACK報文響應CONNECT報文,然後斷開客戶端的連線

(3) 連線標誌(Connect Flags)

連線標誌包含一些用於指定MQTT連線行為的引數,它還指出有效載荷中的欄位是否存在,伺服器必須驗證CONNECT控制報文的連線標誌第0位是否為0,如果不為0必須斷開客戶端連線,具體說明如下:

Clean Session:這個標誌位用於控制會話的生存時間。如果清理會話(CleanSession)標誌被設定為0,並且和這個客戶端識別符號有關聯的會話伺服器必須恢復當前會話(使用客戶端識別符號識別)的狀態與客戶端的通訊;如果還沒有和這個客戶端識別符號有關聯的會話,服務端必須建立一個新的會話,並如果在連線斷開之後,客戶端和服務端必須儲存相關的會話資訊,伺服器必須將之後的QoS1和QoS2級別的訊息會話狀態儲存起來,當然伺服器也可以儲存滿足相同條件的QoS0級別的訊息。如果清理會話(CleanSession)標誌被設定為1,客戶端和伺服器必須丟棄之前的會話並開始一個新的會話,這時會話僅持續和網路連線一樣長的時間

客戶端的會話狀態包括:

  • 已經傳送給伺服器,但是還沒有完成確認的QoS1和QoS2級別的訊息
  • 已從伺服器接收,但是還沒有完成確認的QoS2級別的訊息

服務端的會話狀態包括:

  • 會話是否存在,即使會話狀態都是空
  • 客戶端的訂閱資訊
  • 已經傳送給客戶端,但是還沒有完成確認的QoS1和QoS2級別的訊息
  • 即將傳輸給客戶端的QoS1和QoS2級別的訊息
  • 已從客戶端接收,但是還沒有完成確認的QoS2級別的訊息
  • 可選,準備傳送給客戶端的QoS0級別的訊息

PS:保留訊息不是伺服器會話狀態的一部分,會話終止時不能刪除保留訊息,一般來說, 客戶端連線時清理會話標誌設定為0或1,清理會話標誌設定為1的客戶端不會收到舊的應用訊息, 而且在每次連線成功後都需要重新訂閱任何相關的主題。 清理會話標誌設定為0的客戶端會收到所有在它連線斷開期間釋出的QoS1和QoS2級別的訊息。 因此, 要確保不丟失連線斷開期間的訊息, 需要使用QoS1或QoS2級別, 同時將清理會話標誌設定為0。 當客戶端決定之後不再使用這個會話時,應該將清理會話標誌設定為1再連線一次, 然後斷開連線,這時會把會話狀態清除

Will Flag:如果遺囑標誌Will Flag被設定為1, 遺囑訊息Will Message必須被儲存在伺服器上,在之後客戶端網路連線關閉時伺服器必須釋出這個遺囑訊息, 除非伺服器收到DISCONNECT報文時刪除了這個遺囑訊息。如果遺囑標誌被設定為1, 連線標誌中的Will QoS和Will Retain欄位會被伺服器使用到, 同時CONNECT報文中的有效載荷中必須包含Will Topic和Will Message欄位, 遺囑訊息一旦被髮布或者伺服器收到了客戶端傳送的DISCONNECT報文, 遺囑訊息就必須從儲存的會話狀態中移除。如果遺囑標誌被設定為0, 連線標誌中的Will QoS和Will Retain字也必須設定為0, 並且CONNECT報文中的有效載荷中不能包含Will Topic和Will Message欄位。服務端應該迅速釋出遺囑訊息,但在關機或故障的情況下,伺服器可以推遲遺囑訊息的釋出直到之後的重新啟動

Will Qos:一共兩位,用於指定釋出遺囑訊息時使用的服務質量等級。如果遺囑標誌被設定為0, 遺囑QoS也必須設定為0 。如果遺囑標誌被設定為1, 遺囑QoS的值可以等於0、1、 2

Will Retain:如果遺囑訊息被髮布時需要保留需要指定這一位的值,如果遺囑標誌被設定為0, 遺囑保留Will Retain標誌也必須設定為0。如果遺囑保留被設定為0,伺服器必須將遺囑訊息當作非保留訊息釋出,如果遺囑保留被設定為1,伺服器必須將遺囑訊息當作保留訊息釋出

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

Password Flag:如果密碼( Password) 標誌被設定為0, 有效載荷中不能包含密碼欄位,如果密碼( Password) 標誌被設定為1, 有效載荷中必須包含密碼欄位,如果使用者名稱標誌被設定為0, 密碼標誌也必須設定為0

(4) 保持連線(Keep Alive)

保持連線(Keep Alive)是一個以秒為單位的時間間隔, 它是指在客戶端傳輸兩個控制報文的之間允許的最大時間間隔。 客戶端要保證控制報文傳送的時間間隔不超過保持連線的值。 如果沒有任何其它的控制報文可以傳送, 客戶端必須傳送一個PINGREQ報文給伺服器,而且客戶端任何時候都可以傳送PINGREQ報文,並且可以使用PINGRESP報文判斷網路和伺服器的活動狀態。如果保持連線的值非零,並且伺服器在一點五倍的保持連線時間內沒有收到客戶端的任何控制報文,它必須斷開客戶端網路連線, 認為網路連線已斷開 。客戶端傳送了PINGREQ報文之後,如果在合理的時間內仍沒有收到PINGRESP報文,它應該關閉到伺服器的網路連線。保持連線的值為零表示關閉保持連線功能, 這意味著, 伺服器不需要因為客戶端不活躍而斷開連線。

注意: 不管保持連線的值是多少, 任何時候只要服務端認為客戶端是不活躍或無響應的,可以斷開客戶端的連線。保持連線的實際值是由應用指定的, 一般是幾分鐘,允許的最大值是18小時12分15秒

示例

3、有效載荷
CONNECT報文的有效載荷payload包含一個或多個以長度為字首的欄位, 可變報頭中的標誌決定是否包含這些欄位: 客戶端識別符號, 遺囑主題, 遺囑訊息, 使用者名稱, 密碼

(1) 客戶端識別符號:伺服器使用客戶端識別符號 (ClientId) 識別客戶端。 連線伺服器的每個客戶端都有唯一的客戶端標(ClientId),客戶端和伺服器都使用ClientId識別兩者之間的MQTT會話狀態。客戶端識別符號 (ClientId) 必須存在而且必須是CONNECT報文有效載荷的第一個欄位,伺服器允許1到23個位元組長的UTF-8編碼的客戶端識別符號, 在客戶端識別符號只能包含這些字元: 大字母和數字,伺服器可以允許客戶端提供一個零位元組的客戶端識別符號 (ClientId) ,這時伺服器會為客戶端分配唯一的客戶端識別符號並正常處理這個CONNECT報文,如果客戶端提供了一個零位元組的客戶端識別符號, 它必須同時將清理會話標誌設定為1,如果客戶端提供的ClientId為零位元組且清理會話標誌為0, 伺服器必須傳送返回碼為0x02(表示識別符號不合格)的CONNACK報文來響應客戶端, 然後關閉網路連線,另一方面如果伺服器拒絕了這個ClientId,它必須傳送返回碼為0x02(表示識別符號不合格)CONNACK報文響應客戶端然後關閉網路連線。總之,客戶端實現可以提供一個方便的方法用於生成隨機的ClientId,但當清理會話標誌被設定為0時應該主動放棄使用這種方法

(2) 遺囑主題:如果遺囑標誌被設定為1,有效載荷的下一個欄位是遺囑主題(Will Topic),遺囑主題必須是UTF-8編碼字串

(3) 遺囑訊息:如果遺囑標誌被設定為1, 有效載荷的下一個欄位是遺囑訊息,遺囑訊息定義了將被髮布到遺囑主題的應用訊息,  這個欄位由長度為兩位元組和遺囑訊息的有效載荷組成, 長度給出了跟在後面的資料的位元組數, 不包含長度欄位本身佔用的兩個位元組。遺囑訊息被髮布到遺囑主題時, 它的有效載荷只包含這個欄位的資料部分, 不包含開頭的兩個長度的位元組

(3) 使用者名稱:如果使用者名稱(User Name)標誌被設定為1, 有效載荷的下一個欄位就是它, 使用者名稱必須是UTF-8編碼字串,伺服器可以將它用於身份驗證和授權

(3) 密碼:如果密碼(Password)標誌被設定為1, 有效載荷的下一個欄位就是它,密碼欄位包含兩位元組的長度欄位, 長度表示二進位制資料的位元組數( 不包含長度欄位本身佔用的兩個位元組),後面跟著0到65535位元組的二進位制資料

4、連線後的響應Response
如果伺服器確定協議是MQTT 3.1.1, 那麼它按照下面的方法驗證連線請求。
(1) 網路連線建立後, 如果服務端在合理的時間內沒有收到CONNECT報文, 服務端應該關閉這個連線。
(2) 服務端必須按照要求驗證CONNECT報文, 如果報文不符合規範, 服務端不傳送CONNACK報文直接關閉網路連線
(3) 服務端可以檢查CONNECT報文的內容是不是滿足任何進一步的限制, 可以執行身份驗證和授權檢查,如果任何一項檢查過, 它應該傳送一個適當的、返回碼非零的CONNACK響應, 並且必須關閉這個網路連線。

如果驗證成功, 服務端會執行下列步驟。
(1) 如果ClientId表明客戶端已經連線到這個服務端, 那麼服務端必須斷開原有的客戶端連線
(2) 服務端必須執行清理會話的過程
(3) 服務端必須傳送返回碼為零的CONNACK報文作為CONNECT報文的確認響應
(4) 開始訊息分發和保持連線狀態監視

PS:允許客戶端在傳送CONNECT報文之後立即傳送其它的控制報文; 客戶端不需要等待服務端的CONNACK報文。 如果服務端拒絕了CONNECT, 它不能處理客戶端在CONNECT報文之後傳送的任何資料客戶端通常會等待一個CONNACK報文。 然而客戶端有權在收到CONNACK之前傳送控制報文, 由於不需要維持連線狀態, 這可以簡化客戶端的實現

二.CONNACK報文

伺服器傳送CONNACK報文響應客戶端CONNECT報文。 伺服器傳送給客戶端的第一個報文必須是CONNACK。如果客戶端在合理的時間內沒有收到服務端的CONNACK報文, 客戶端應該關閉網路連線

1、固定報頭

剩餘長度欄位表示可變報頭的長度, 對於CONNACK報文這個值等於2

2、可變報頭

(1) 連線確認標誌 Connect Acknowledge Flags:位7-1是保留位且必須設定為0,第0位(SP)是當前會話(Session Present)標誌。如果伺服器收到清理會話(CleanSession)標誌為1的連線,除了將CONNACK報文中的返回碼設定為0之外,還必須將CONNACK報文中的當前會話設定(Session Present) 標誌為0,如果伺服器收到一個CleanSession為0的連線, 當前會話標誌的值取決於服務端是否已經儲存了ClientId對應客戶端的會話狀態。如果伺服器已經儲存了會話狀態, 它必須將CONNACK報文中的當前會話標誌設定為1 。如果伺服器沒有已儲存的會話狀態,它必須將CONNACK報文中的當前會話設定為0,當然還需要將CONNACK報文中的返回碼設定為0 ,如果服務端傳送了一個包含非零返回碼的CONNACK報文,它必須將當前會話標誌設定為0

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

如果認為上表中的所有連線返回碼都不太合適, 那麼服務端必須關閉網路連線, 並不需要傳送CONNACK報文

相關文章