--- tags: MQTT, IoT --- # MQTT v3.1.1規格書 MQTT(Message Queuing Telemetry Transport): 訊息序列遙測傳輸 OASIS 國際標準 發表時間: 29 October 2014 資料連結: > [原文版](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html ) > > [中文版](https://www.zybuluo.com/khan-lau/note/1326839?fbclid=IwAR2oArH4FwpfLOAR-2bbL5SPkZNbGpeEzqw3jptJPzBqTR_u9ucu8FXdSxI) 10 August 2020 ## **1. Introduction** ### 1.2 Terminology #### **Network Connection:** * client透過它連結到server * 提供有序的(ordered)、可靠的(lossless)、雙向(both directions)字串流傳輸 #### **Application Message:** Application Messages透過MQTT傳輸時要帶著***QoS & Topic Name***. #### **Client:** > A program or device that uses MQTT. 透過網路連結上server,提供以下功能: * 發布Application Messages * 訂閱Application Messages * 取消訂閱Application Messages * 與server取消連線 #### **Server:** > A program or device that ***acts as an intermediary*** between Clients which publish Application Messages and Clients which have made Subscriptions. 提供以下功能: * 同意client連結 * 同意client發佈 * 訂閱、取消訂閱處理 * 轉發Application Messages給訂閱者 #### **Subscription:** > A Subscription comprises a ***Topic Filter*** and a ***maximum QoS***. Session裡的每個Subscription有不同的Topic Filter. #### **Session(通信期):** > A stateful interaction between a Client and a Server. 一個Session可以包含一至多個Subscription. #### **Topic Name:** > The ***label*** attached to an Application Message which is matched against the Subscriptions known to the Server. #### **Topic Filter:** > An ***expression*** contained in a Subscription, to indicate an interest in one or more topics. Filter中可以包含***萬用字元*** (wildcard characters). ex. SQL中LIKE %string%的'%' -> 匹配零個或多個字元 #### **MQTT Control Packet:** > The MQTT specification defines fourteen different types of Control Packet PUBLISH packet就是其中一種Control Packet,用於傳輸Application Message. 4 bits空間記錄這14種type. 2.1將詳細介紹 ### 1.5 Data representations > Text fields in the Control Packets described later are encoded as ***UTF-8 strings***. 其中有一些區段的字是被禁止的,自行查閱規格書 --- ## **2. MQTT Control Packet format** ### 2.1 Structure of an MQTT Control Packet MQTT協議是透過交換MQTT Control Packet達成的, 而Control Packet內容可分為三部分: ![](https://i.imgur.com/MLFEfxi.jpg) 後面章節將詳細說明各部分功能。 ### 2.2 Fixed header 每個Control Packet都必定有Fixed header,以下為fixed header format: ![](https://i.imgur.com/cgEToXw.jpg) #### **MQTT Control Packet type:** > Represented as a 4-bit unsigned value 共有14種不同type,其中0000與1111是被保留的: ![](https://i.imgur.com/tNcaVeD.jpg) #### **Flags:** 透過Flags可以為type做額外的細分(ex.PUBLISH設定QoS...),但目前v3.1.1大部分都是被保留的。 ![](https://i.imgur.com/om2yWVq.jpg) #### **Remaining Length:** > The Remaining Length is the number of bytes remaining within the current packet, including data in the ***variable header*** and the ***payload***. 最多允許4個Bytes表示,每個Byte的最高位若為1,表示還有後續Byte存在。 ex. 127(01111111) -> 128(10000000,00000001) >仔細看128的表示方式,跟我們一般讀二進制的方式很不一樣: >* 第一組(Byte)是最低位,依序變高。 >* 每組(Byte)的最高位僅表達有沒有後續的Byte而已,不列入運算中 ex. 10000000,00000001 -> 00000001 ~~1~~0000000 -> 000000010000000(B) -> 128 因此一Byte可以表示$2^7$,最高(4Bytes)能表示$2^{7*4}$ -> 256MB的資料。 ![](https://i.imgur.com/wEQRyz1.jpg) ### 2.3 Variable header 部分MQTT Control Packets有這個header。Variable header中的內容不是固定的,依據Packet type的不同有所不同。 其中,Packet Identifier是相當常見的欄位,很多Packet type都有該欄位。 #### **Packet Identifier:** ![](https://i.imgur.com/actPTEi.jpg) Packet Identifier為2Bytes的欄位,出現在*PUBLISH (where QoS > 0), PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK*這些Packet type中。 > QoS=0之PUBLISH Packet 絕不能(MUST NOT)夾帶Packet Identifier 在SUBSCRIBE, UNSUBSCRIBE, and PUBLISH (QoS > 0) 這些Control Packets中: * 必須帶非0的16-bit Packet Identifier * Client送新的packet時,必須給一組unused的Packet Identifier * 若Client是重送(re-send)packet,必須使用與第一個packet一樣的Packet Identifier Server處理完這些control packet後會回傳Acknowledgement Packet。且***Acknowledgement Packet 的Packet Identifier 必須與原control packet 相同*** ,當Client收到ACK後,該組Packet Identifier就會被釋放。其中: * QoS 1 的PUBLISH對應的ACK packet為PUBACK * QoS 2 的PUBLISH對應的ACK packet為PUBCOMP * SUBSCRIBE、UNSUBSCRIBE對應的ACK packet為SUBACK、UNSUBACK 特別注意: > The Client and Server ***assign Packet Identifiers independently*** of each other. As a result, Client Server pairs can participate in concurrent message exchanges using the same Packet Identifiers. > ![](https://i.imgur.com/JO3gLVH.jpg) ### 2.4 Payload 有些MQTT Control Packets有Payload欄位: CONNECT ,PUBLISH(Optional) ,SUBSCRIBE ,SUBACK ,UNSUBSCRIBE。以PUBLISH packet來說Payload就是Application Message,細節將在第三章解釋。 ## **3. MQTT Control Packets** ### 3.1 CONNECT – Client requests a connection to a Server CONNECT Packet是client連上server後送出的***第一且唯一*** 封包。 #### **Fixed header** ![](https://i.imgur.com/w6gCDyj.jpg) #### **Variable header** CONNECT Packet的variable header按以下四部分順序組成: * Protocol Name: Protocol Name是固定的且未來也不會更改的,用UTF-8來表示"MQTT"這四個字母,如下圖。 ![](https://i.imgur.com/I3Wt2m7.jpg) * Protocol Level: 8 bit unsigned value表示client目前使用的level(有點像版本),v3.1.1的level是4(00000100),若server不支援client使用的level,必需回傳0x01 (unacceptable protocol level)並切斷連線。 * Connect Flags: 透過一些旗標表示MQTT connection的行為,也能透過Connect Flags知道payload有哪些內容。 ![](https://i.imgur.com/yRyNBvt.jpg) 1. Clean Session 為0時,表示創建一個持久會話(Session),在客戶端斷開連接時,會話仍然保持並保存離線消息,直到會話超時註銷 為1時,表示創建一個新的臨時會話,在客戶端斷開時,會話自動銷毀 2. Will Flag 最後遺囑(Last Will and Testament): 為1時,client需在發送CONNECT訊息時將遺言一併傳給server,當client斷線時,遺言將被server主動發佈至該topic上,will flag與後續will QoS、will retain有直接相關(flag=0 -> QoS、retain=0) 3. Will QoS 設定傳送遺言時的QoS 4. Will Retain 設定遺言是否要被保留(Retain)在server上 5. User Name Flag payload中是否有帶帳戶名 6. Password Flag payload中是否有帶密碼,若user name flag為0,password flag必為0 * Keep Alive: 以秒為單位,當server多久沒收到client訊息,就要判定為斷線(server通常會等1.5個keep alive time才切斷連線)。如果在這時間內client、server都沒有溝通,client須發PINGREQ訊息給server,server收到後則回應一個PINGRESP(若client遲遲沒收到PINGRESP可切斷連線)。 Keep Alive為2 byte,設定為0代表client不會斷線,通常只會設定幾分鐘。而此設定的最大值約為18小時。 #### **Payload** payload中包含Client identifier、Will topic、Will Message、帳戶名與密碼,除了Client identifier外都是optional的。 * Client Identifier: client唯一的識別碼,在處理QoS1、2時會用到。長度限制為1~23個字 * Will Topic & Will Message: 若variable header中will flag為1,代表此連線將要啟用最後遺囑(Last Will and Testament)機制,則payload就必須包含遺言內容和遺言要發送到哪個主題。 * User Name & Password: 若variable header中Username、Password flag為1,代表此連線需要帳號與密碼,則payload就必須包含帳號和密碼。 ### 3.2 CONNACK – Acknowledge connection request CONNACK Packet是client連上server後收到的***第一*** 個封包。 #### **Fixed header** ![](https://i.imgur.com/m7DvyeI.jpg) CONNACK Packet Fixed header的Remaining Length一定為2(Variable header固定2 Bytes)。 #### **Variable header** ![](https://i.imgur.com/UQswxVi.jpg) * Connect Acknowledge Flags: 1-7 bits為保留位元(必為0),Bit 0為Session Present Flag,其代表server是否存在session state,當client連線時,server透過client id搜尋是否存在session state,並設定session present flag值。 注意以下兩點: * 當CONNECT Packet中的Clean Session為1時,不論是否存在session state,session present flag皆為0 * 若return code不為0時,session present flag必為0 * Connect Return Code: Return Code表示連結的狀態,如下表: ![](https://i.imgur.com/7z1bbWh.jpg) 除了0以外目前皆為拒絕 #### **Payload** CONNACK Packet無payload ### 3.3 PUBLISH – Publish message #### **Fixed header** PUBLISH Packet的fixed header format如下表: ![](https://i.imgur.com/9EEHh2g.jpg) * DUP: DUP flag代表此PUBLISH packet是否重傳,若0代表為第一次傳,1代表為重傳(re-delivery)。對server(broker)而言,進與出是不同的,因此收到的PUBLISH與送出的PUBLISH DUP是獨立的 * QoS: QoS對應處理方式如下表: ![](https://i.imgur.com/SE6vfW9.jpg) * RETAIN: 設定訊息是否要保留在server上,當client發送PUBLISH Message給Server上的某個Topic時,如果將此flag設為1,則Server將此訊息發佈並必須將此訊息保留。 當有一個新的client對此Topic進行訂閱,則Server必須把最後一則Retain flag設為1的訊息傳送給該client。被設為Retain的訊息必須保留直到Server重啟為止。 此機制會適用於訊息與訊息之間會有一段時間的場景,也就是訊息的發佈(Publish)可能不是那麼的頻繁的情形 #### **Variable header** PUBLISH Packet的variable header中包含: * Topic Name: UTF-8編碼的字串,必須是一個明確的主題定義,不能為萬用字元(wildcard characters) * Packet Identifier: Message ID會使用在QoS1、2的訊息中,為16bit無符號的整數,代表***特定方向*** 訊息唯一的id(server2client與client2server不同),每個client都會維護他們自己的Message ID列表。 Message ID不能為0,它會被視為無效的Message ID #### **Payload** PUBLISH Packet的payload為要發佈的訊息內容(可為0) #### **Response** 若QoS為1、2,收到後必須回應PUBACK、PUBREC packet ### 3.4 PUBACK – Publish acknowledgement PUBACK packet是用來回應QoS1的PUBLISH packet #### **Fixed header** ![](https://i.imgur.com/z03rf9A.jpg) #### **Variable header** PUBACK packet的variable header只帶PUBLISH packet的Packet Identifier #### **Payload** PUBACK Packet無payload ### 3.5 PUBREC – Publish received (QoS 2 publish received, part 1) PUBREC packet是用來回應QoS2的PUBLISH packet,是QoS2流程下第二個packet #### **Fixed header** ![](https://i.imgur.com/750B3Ah.jpg) #### **Variable header** PUBREC packet的variable header只帶PUBLISH packet的Packet Identifier #### **Payload** PUBREC Packet無payload ### 3.6 PUBREL – Publish release (QoS 2 publish received, part 2) PUBREL packet是用來回應QoS2的PUBREC packet,是QoS2流程下第三個packet #### **Fixed header** ![](https://i.imgur.com/J1n6Gj4.jpg) 注意:保留區段必須填入0010 #### **Variable header** PUBREC packet的variable header只帶PUBREC packet的Packet Identifier #### **Payload** PUBREC Packet無payload ### 3.7 PUBCOMP – Publish complete (QoS 2 publish received, part 3) PUBCOMP packet是用來回應QoS2的PUBREL packet,是QoS2流程下第四也是最終的packet #### **Fixed header** ![](https://i.imgur.com/620XE21.jpg) #### **Variable header** PUBOMP packet的variable header只帶PUBREL packet的Packet Identifier #### **Payload** PUBREC Packet無payload ### 3.8 SUBSCRIBE - Subscribe to topics SUBSCRIBE packet讓client可以向server訂閱一或多個Topic。當有訊息對主題發佈時,server會將訊息當作PUBLISH Message送給訂閱的client。SUBSCRIBE packet也定義了QoS level,表示它期望以何種QoS level來接收訊息。 #### **Fixed header** ![](https://i.imgur.com/NSRy7IB.jpg) 注意:保留區段必須填入0010 #### **Variable header** SUBSCRIBE packet的variable header只帶自身的Packet Identifier #### **Payload** SUBSCRIBE packet的payload包含一或多對主題名( Topic Filter)與QoS,如下表: ![](https://i.imgur.com/zjd1L5P.jpg) #### **Response** server接收到SUBSCRIBE packet後必須回傳SUBACK packet,且client可能在還沒收到SUBACK前就收到PUBLISH ### 3.9 SUBACK – Subscribe acknowledgement server接收到SUBSCRIBE packet後必須回傳SUBACK packet,且內容需帶return code(數量與SUBSCRIBE的Topic Filter一致) #### **Fixed header** ![](https://i.imgur.com/1Vctd82.jpg) #### **Variable header** SUBACK packet的variable header只帶與SUBSCRIBE相同的Packet Identifier #### **Payload** SUBACK packet的payload中需帶return code,順序、數量必須和SUBSCRIBE的一致,其用途為回傳SUBSCRIBE訂閱列表中各topic的最大QoS ![](https://i.imgur.com/A4LdLth.jpg) ``` Allowed return codes: 0x00 - Success - Maximum QoS 0 0x01 - Success - Maximum QoS 1 0x02 - Success - Maximum QoS 2 0x80 - Failure ``` ### 3.10 UNSUBSCRIBE – Unsubscribe from topics UNSUBSCRIBE packet是由client送給server,用於取消訂閱topic #### **Fixed header** ![](https://i.imgur.com/4OXAPvF.jpg) 注意:保留區段必須填入0010 #### **Variable header** UNSUBSCRIBE packet的variable header只帶自身的Packet Identifier #### **Payload** 與SUBSCRIBE類似,UNSUBSCRIBE packet的payload會包含一個主題名稱列表,代表該Client想要取消訂閱的主題 #### **Response** 取消註冊成功,Server會回應一個UNSUBACK Message給client ### 3.11 UNSUBACK – Unsubscribe acknowledgement server接收到UNSUBSCRIBE packet後必須回傳UNSUBACK packet #### **Fixed header** ![](https://i.imgur.com/FffTfs5.jpg) #### **Variable header** UNSUBACK packet的variable header只帶與UNSUBSCRIBE相同的Packet Identifier #### **Payload** UNSUBACK Packet無payload ### 3.12 PINGREQ – PING request PINGREQ是由client發起,用來確定server與網路還活著(alive),同時也將自身狀態回報給server,server收到後將會歸零Keep Alive timer(CONNECT packet提過) #### **Fixed header** ![](https://i.imgur.com/nvXvfif.jpg) #### **Variable header** PINGREQ Packet無Variable header #### **Payload** PINGREQ Packet無payload ### 3.13 PINGRESP – PING response PINGRESP用途為回應client的PINGREQ,並向client回報狀態(server還活著) #### **Fixed header** ![](https://i.imgur.com/znu51nR.jpg) #### **Variable header** PINGRESP Packet無Variable header #### **Payload** PINGRESP Packet無payload ### 3.14 DISCONNECT – Disconnect notification DISCONNECT packet是client送給server的最後一包control packet,表示client將要斷掉它的TCP/IP連線並完全清除(will message...)。 #### **Fixed header** ![](https://i.imgur.com/zzsPhXw.jpg) #### **Variable header** DISCONNECT Packet無Variable header #### **Payload** DISCONNECTP Packet無payload #### **Response** server收到後不能再做出任何回應 ## **4. Operational behavior**