2014年2月13日

MQTT(三)CONNECT Message

前言:

前一篇提到MQTT有很多種Message Type用來實現協定。

而這次會特別把CONNECT Message拿出來講,主要是因為在CONNECT Message裡面有用到了許多的flag,而這些flag又會跟MQTT的一些特性有關,因此有必要將之獨立出來說明。

Message Format

在開始談CONNECT message之前,讓我們先來看看MQTT的訊息格式。 MQTT的訊息格式如下圖所示:

其中:

  • Fixed Header每個類型的訊息都會有,至少為2 byte。
  • Variable Header會根據訊息類型而有所不同,某些訊息類型甚至沒有variable header。
  • Payload和Variable Header一樣,也會根據訊息類型不同而有所不同,某些訊息類型沒有Payload。

CONNECT Message

接著讓我們來看看今天的主角CONNECT Message,首先先看看它的Fixed Header。

Fixed Header:

bit 7 6 5 4 3 2 1 0
byte 1 Message Type(1) DUP flag QoS level RETAIN
0 0 0 1 x x x x
byte 2 Remaining Length

在CONNECT Message裡面,fixed header並不會用到太多欄位,因此這邊只會簡單介紹一下他們。

  • Message Type:每種類型的Message都要用到,要根據想用的訊息類型填上相對應的值,值可以參考先前貼的文章MQTT(二)Message Type and Flows。這邊由於是CONNECT Message的關係,因此會填上0001。

  • DUP flag:標記此訊息為重複(duplicate)的訊息,只有在PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE才會用到。

  • QoS level:設定此訊息的QoS level,只有在PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE才會用到。

  • RETAIN:設定訊息是否要保留在server上,此特性只有PUBLISH才會用到。

  • Remaining Length:此欄位記錄當前的Message,它的Variable header和Payload總共的長度為何,此欄位不一定就是1 byte,它是可變得,最多到4 byte。而且它會用特殊編碼來存放值,最高可以呈現到256MB,也就是說,你的Variable header + payload最大可以達到256MB。至於它編碼的部分可以去參考MQTT V3.1 Protocol Specification, Fixed header的介紹,會寫的比較詳細,這邊就不再多描述了。

看完上述的介紹之後會發現到,CONNECT Message的Fixed Header其實沒用到什麼特別的flag,只需要定對Message Type,然後根據編碼方式寫上正確的Remaining Length即可。

接著讓我們繼續往下看,再來是第二個Herader,也就是Variable Header。


Variable Header:

下面為一個CONNECT Message其Variable Header範例:

Description 7 6 5 4 3 2 1 0
byte1 - byte8 Protocol Name (MQIsdp)
byte9 Version (3)
Connect Flags
byte 10 User name flag (1)
Password flag (1)
Will RETAIN (0)
Will QoS (01)
Will flag (1)
Clean Session (1)
1 1 0 0 1 1 1 x
byte 11 Keep Alive MSB (0) 0 0 0 0 0 0 0 0
byte 12 Keep Alive LSB (10) 0 0 0 0 1 0 1 0

主要分為三塊,分別為協定的資訊(byte1 ~ byte9)、此次連線的特性設定(byte 10)以及連線逾時時間設定。以下說明這些flag的用意:

Protocol name 和 Protocol version

協定的資訊包括協定的名稱和版本號碼,名稱為MQIsdp,版本號碼為3(0x03)。

Connect flags:

Connect flag原本有四個,分別為Clean session、Will、Will QoS和Retain flags,而MQTT3.1又新增了兩個Username和Password,底下就來一一介紹他們。

  • clean session flag

    設定為0,代表是當client斷線時,server必須要把該位client訂閱哪個主題記錄下來。再該client斷線的期間,如果有QoS 1和QoS 2的訊息被發佈到該主題了,則server必須把訊息儲存下來,等到該client重新連線時能收到它沒收到的訊息。

    設定為1,代表當client斷線時,server必須要清掉該位client所有的狀態,當client重新連線時,必須要再重新訂閱它感興趣的主題。

  • will flag、will QoS和will Retain flag

    這三個flag,就是在MQTT簡介裡被提到的 最後遺囑(Last Will and Testament) 機制所用的flag。這機制是這樣的,client在一開始發送CONNECT訊息給server要求建立連線時,就把要對哪個主題說什麼遺言一起傳給server,當它在不正常的情況下斷線時(比如說網路連線斷掉、裝置故障等等),則這些訊息就會被server主動發佈到該主題上。如果是client主動發送DISCONNECT訊息給server要求斷線時,則此機制將不會有作用。

    要啟動此機制,首先就是要將Will flag設為1,這樣就代表要啟用,之後你設定遺言的QoS level為何,server會依照你設定的QoS level來幫你傳送訊息,最後設定此此則遺言是否要保留(Retain)在server上。如果有設定Will flag,則在pyaload內會需要定義Will Topic和Will Message,也就是要對哪個主題發送什麼樣的遺言。

  • Username and Password flag

    最後兩個flag為Useername和Password,意思是說此連線是否會包含帳號與密碼,如果有設定,則需要在payload內把帳號和密碼一起傳給server。要注意的是Password flag有設定而Username flag沒設定,此狀況是不被允許的。

Keep Alive timer

以秒為單位,指的是當server多久沒接收到從client發送過來的訊息時,就要認為與該client的網路連線已經斷掉了。此設定可以讓server不需要等待時間較長的TCP/IP timeout來得知網路狀況。Client有責任在此定義的時間內對server發過來的訊息作回應。如果在這時間內client和server都沒有訊息互傳的話,則client必須發送一個PINGREQ訊息給server,而server則回應一個PINGRESP message。

server會給client一個寬限時間,也就是會等1.5個Keep Alive timer時間,如果此段時間內client都沒送訊息過來,則server必須將此client斷線。

而client如果在Keep Alive time期間發送出PINGREQ訊息,卻一直沒收到PINGRESP訊息,則client必須關閉TCP/IP socket連線。

Keep Alive為2 byte,設定為0代表client不會斷線,通常只會設定幾分鐘。而此設定的最大值約為18小時。

Payload:

最後為CONNECT Message的payload,payload裡面包含什麼會跟你在variable header內的設定有關係,以下就來介紹payload裡面有些什麼。

Client Identifier

client唯一的識別碼,此識別碼在處理QoS level 1和2時會用到。長度限制為1~23個字,若超過23個字則會發生 Identifier Rejected的錯誤。

Will Topic and Will Message

如果在variable內有設定Will flag的話,代表此連線將要啟用最後遺囑(Last Will and Testament)機制,則payload就必須包含遺言內容和遺言要發送到哪個主題。

Username and Password

如果在variable內有設定Username flag和Password flag的話,代表此連線需要帳號與密碼,則payload就必須包含帳號和密碼。

小結

本篇介紹了MQTT的CONNECT Message,並介紹了一些MQTT的特性,讓程式開發人員在使用MQTT的相關library開發時,會知道建立連線可以設定的參數為何,其意義又為何。了解這些特性也會對應用MQTT的的架構規劃有所幫助。

參考:

MQTT V3.1 Protocol Specification