---
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內容可分為三部分:

後面章節將詳細說明各部分功能。
### 2.2 Fixed header
每個Control Packet都必定有Fixed header,以下為fixed header format:

#### **MQTT Control Packet type:**
> Represented as a 4-bit unsigned value
共有14種不同type,其中0000與1111是被保留的:

#### **Flags:**
透過Flags可以為type做額外的細分(ex.PUBLISH設定QoS...),但目前v3.1.1大部分都是被保留的。

#### **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的資料。

### 2.3 Variable header
部分MQTT Control Packets有這個header。Variable header中的內容不是固定的,依據Packet type的不同有所不同。
其中,Packet Identifier是相當常見的欄位,很多Packet type都有該欄位。
#### **Packet Identifier:**

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.
> 
### 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**

#### **Variable header**
CONNECT Packet的variable header按以下四部分順序組成:
* Protocol Name:
Protocol Name是固定的且未來也不會更改的,用UTF-8來表示"MQTT"這四個字母,如下圖。

* 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有哪些內容。

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**

CONNACK Packet Fixed header的Remaining Length一定為2(Variable header固定2 Bytes)。
#### **Variable header**

* 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表示連結的狀態,如下表:

除了0以外目前皆為拒絕
#### **Payload**
CONNACK Packet無payload
### 3.3 PUBLISH – Publish message
#### **Fixed header**
PUBLISH Packet的fixed header format如下表:

* DUP:
DUP flag代表此PUBLISH packet是否重傳,若0代表為第一次傳,1代表為重傳(re-delivery)。對server(broker)而言,進與出是不同的,因此收到的PUBLISH與送出的PUBLISH DUP是獨立的
* QoS:
QoS對應處理方式如下表:

* 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**

#### **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**

#### **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**

注意:保留區段必須填入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**

#### **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**

注意:保留區段必須填入0010
#### **Variable header**
SUBSCRIBE packet的variable header只帶自身的Packet Identifier
#### **Payload**
SUBSCRIBE packet的payload包含一或多對主題名( Topic Filter)與QoS,如下表:

#### **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**

#### **Variable header**
SUBACK packet的variable header只帶與SUBSCRIBE相同的Packet Identifier
#### **Payload**
SUBACK packet的payload中需帶return code,順序、數量必須和SUBSCRIBE的一致,其用途為回傳SUBSCRIBE訂閱列表中各topic的最大QoS

```
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**

注意:保留區段必須填入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**

#### **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**

#### **Variable header**
PINGREQ Packet無Variable header
#### **Payload**
PINGREQ Packet無payload
### 3.13 PINGRESP – PING response
PINGRESP用途為回應client的PINGREQ,並向client回報狀態(server還活著)
#### **Fixed header**

#### **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**

#### **Variable header**
DISCONNECT Packet無Variable header
#### **Payload**
DISCONNECTP Packet無payload
#### **Response**
server收到後不能再做出任何回應
## **4. Operational behavior**