前言
緊接著上篇初步介紹,本文為第二篇,主要梳理MQTT-SN 1.2協議中定義的消息格式。
通用消息格式
消息頭部
- 長度要么是1個字節,要么3個字節表示,并且自身也會包含在其內。一個字節可表示256長度,一般情況下,完全夠用了。
- 只需要判斷第一個字節是否為 0x01,若是那么長度為3個字節表示,剩下的兩個字節會表示真正的消息長度,最大長度為65535
- 否則長度就是一個字節表示,256個長度,大部分消息長度都是一個字節,除非特別提醒
備注:
MQTT-SN不支持消息的分片和重組。底層網絡所定義數據包長度若小于MQTT-SN消息的最大長度,自身進行的分片和重組,對MQTT-SN協議本身不受影響。
MQTT-SN消息類型
MQTT-SN定義的消息類型數量眾多,超過25個,感覺有些頭大。
消息類型值 |
消息類型名稱 |
說明 |
0x00 |
ADVERTISE |
廣播消息 |
0x01 |
SEARCHGW |
尋找網關 |
0x02 |
GWINFO |
網關信息 |
0x03 |
reserved |
沒有使用到 |
0x04 |
CONNECT |
發起連接 |
0x05 |
CONNACK |
連接確認 |
0x06 |
WILLTOPICREQ |
遺囑主題請求 |
0x07 |
WILLTOPIC |
遺囑主題確認 |
0x08 |
WILLMSGREQ |
遺囑消息請求 |
0x09 |
WILLMSG |
遺囑消息確認 |
0x0A |
REGISTER |
注冊主題 |
0x0B |
REGACK |
注冊確認 |
0x0C |
PUBLISH |
發布消息 |
0x0D |
PUBACK |
發布確認 |
0x0E |
PUBCOMP |
發布環節消息 |
0x0F |
PUBREC |
發布環節消息 |
0x10 |
PUBREL |
發布環節消息 |
0x11 |
reserved |
保留字段 |
0x12 |
SUBSCRIBE |
訂閱主題 |
0x13 |
SUBACK |
訂閱確認 |
0x14 |
UNSUBSCRIBE |
退訂 |
0x15 |
UNSUBACK |
退訂確認 |
0x16 |
PINGREQ |
Ping請求 |
0x17 |
PINGRESP |
Ping響應 |
0x18 |
DISCONNECT |
斷開 |
0x19 |
reserved |
保留字段 |
0x1A |
WILLTOPICUPD |
遺囑主題更新 |
0x1B |
WILLTOPICRESP |
遺囑主題更新確認 |
0x1C |
WILLMSGUPD |
遺囑消息更新 |
0x1D |
WILLMSGRESP |
遺囑消息更新確認 |
0x1E-0xFD |
reserved |
保留字段 |
0xFE |
轉發封裝標志 |
用于轉發 |
消息可變部分
可變字段很多,與MQTT相比,多了:
- 持續時長字段(Duration)
- 標識符Flags有所不同,下面表格進行說明
- 網關地址(GwAdd),可變長度,但依賴于底層網絡,在ZigBee網絡中2個字節長度
- 一個字節網關Id(GwId)
- 協議Id(ProtocolId),一個字節,唯一值 0x01,統一表示協議名稱和協議名稱
- 廣播路徑跳數(廣播路徑深度/廣播輻射范圍),Radius,一個字節表示,0x00表示廣播給當前網絡中所有節點
- CONNECT/REGISTER/SUBSCRIBE/PUBLISH等消息對應回執中都會包含返回碼Recode Code,見下表格
返回值 |
返回值含義 |
0x00 |
接受請求(Accepted) |
0x01 |
因擁塞拒絕(Rejected: congestion),一般需要接收方等待T_WAIT時間長 |
0x02 |
因非法主題標識符拒絕(Rejected: invalid topic ID) |
0x03 |
因不支持拒絕(Rejected: not supported) |
0x04 - 0xFF |
保留,沒有使用到 |
具體消息格式說明
ADVERTISE
網關周期性會對當前網絡下所有客戶端、節點進行廣播,用于客戶端發現可用網關。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x05 |
1 |
MsgType |
0x00 |
2 |
GwId |
網關需要吧自身標識符包含其中 |
3-4 |
Duration |
網關的下次廣播間隔時長,單位秒 |
SEARCHGW
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x03 |
1 |
MsgType |
0x01 |
2 |
Radius |
廣播半徑深度,同時也是只是給當前網絡傳輸層 |
客戶端主動尋找網關進行廣播的消息,廣播路徑范圍受限于當前網絡環境下的客戶端部署密度,比如只有1跳廣播在非常密集的網絡環境下客戶端都可以彼此互相訪問。
GWINFO
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態確定 |
1 |
MsgType |
0x02 |
2 |
GwId |
網關Id |
3-n |
GwAdd* |
一個網關地址,僅僅由客戶端發出消息時,此字段才存在 |
GWINFO作為對SEARCHGW消息的響應:
- 若由網關發出,則無GwAdd字段
- 若來自于客戶端,需要包含網關地址
CONNECT
客戶端向網關發出建立連接的消息。
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x04 |
2 |
Flags |
標志位 |
3 |
ProtocolId |
0x01,表示協議版本和協議名稱 |
4-5 |
Duration |
存活持續時長 |
6-n |
ClientId |
客戶端標識符,1-23個字節表示的字符串 |
在CONNECT消息標志位具體表示如下:
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
X |
X |
X |
0/1 |
0/1 |
X |
在Flags中使用到的標志位:
- Will:若為1,客戶端會在稍后請求遺囑主題和遺囑消息
- CleanSession:不但表示訂閱持久化,同時也被可擴展到遺囑主題和遺囑消息中
CONNACK
網關對客戶端發出CONNECT消息的響應。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x03 |
1 |
MsgType |
0x05 |
2 |
ReturnCode |
接受值0x00,拒絕為0x01-0x03,具體見上文RecodeCode定義 |
WILLTOPICREQ
根據客戶端CONNECT標志位中WILL字段為true情況下,網關向客戶端發出遺囑主題請求,格式如下:
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x02 |
1 |
MsgType |
0x06 |
只有頭部部分,很簡單。
WILLTOPIC
客戶端作為網關WILLTOPICREQ請求響應消息。下面是一個正常版本的WILLTOPIC消息:
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x07 |
2 |
Flags |
標志位 |
3-n |
WillTopic |
遺囑主題 |
此時的標志位如下
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
X |
0x00-0x02 |
0/1 |
X |
X |
X |
而空的WILLTOPIC也是允許存在的,就兩個字節表示,用于客戶端請求刪除已存在于服務器端的對應遺囑主題和消息。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x02 |
1 |
MsgType |
0x07 |
WILLMSGREQ
根據客戶端CONNECT標志位中WILL字段為真情況下,網關向客戶端發出遺囑消息請求,格式如下:
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x02 |
1 |
MsgType |
0x08 |
只有頭部部分,沒有別的。
WILLMSG
客戶端對網關WILLMSGREQ請求的響應,從而把遺囑消息傳遞給網關進行保存。
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x09 |
2-n |
WillMsg |
客戶端遺囑 |
REGISTER
- 客戶端-->網關,請求主題(topic name)對應的主題標識符(topic id)
- 網關-->客戶端,通知主題(topic name)已經被指派到某個主題標識符(topic id)
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x0A |
2-3 |
TopicId |
客戶端發出,此值為0x0000;服務器發出,需要包含對應于Topic Name的主題標識符 |
4-5 |
MsgId |
自然數,用以標識對應的REGACK確認 |
6-n |
TopicName |
主題名稱,不能太長,盡量不要使用通配符 |
REGACK
客戶端或網關針對REGISTER消息的響應。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x07 |
1 |
MsgType |
0x0B |
2-3 |
TopicId |
對應于Topic Name的主題標識符,被用于PUBLISH消息發布 |
4-5 |
MsgId |
自然數,用以標識對應的REGISTER消息 |
6 |
ReturnCode |
0x00被接受,其它值被拒絕 |
PUBLISH
PUBLISH消息用于客戶端或網關發布消息用:
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x0C |
2 |
Flags |
標志位 |
3-4 |
TopicId |
主題標識符 |
5-6 |
MsgId |
QoS 1-2時需要填充自然值;QoS 0時,值為0x0000 |
7-n |
Data |
用于發布的具體消息內容 |
標識位具體如下:
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
0/1 |
0x00-0x02 |
0/1 |
X |
X |
0b00/0b01/0b10 |
標識位里面各個字段和MQTT協議一致,無須多解釋。
PUBACK
客戶端/網關僅僅對QoS 1/2的PUBLISH消息做出響應。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x07 |
1 |
MsgType |
0x0D |
2-3 |
TopicId |
對應PUBLISH消息中TopicId |
4-5 |
MsgId |
自然數,用以標識對應的REGISTER消息 |
6 |
ReturnCode |
0x00被接受,其它值被拒絕,不同值表示不同拒絕理由 |
處理PUBLISH消息異常?在PUBACK消息中的ReturnCode字段中以相應值體現出來,這就要求接收者處理拒絕理由。
PUBREC, PUBREL, PUBCOMP
只有在PUBLISH消息中QoS 2時,PUBREC, PUBREL, PUBCOMP才會一起登場,否則是沒有出場機會的。消息格式嘛,都很統一:
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x04 |
1 |
MsgType |
0x0F/0x10/0x0E |
2-3 |
MsgId |
對應PUBLISH消息中的MsgId |
SUBSCRIBE
SUBSCRIBE用于客戶端訂閱某個主題的消息。
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x12 |
2 |
Flags |
標志位 |
3-4 |
MsgId |
用于確定對應的訂閱確認SUBACK消息 |
5-N |
TopicId/TopicName |
具體需要根據Flags標志位中TopicIdType進行填充 |
標識位具體如下:
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
0/1 |
0x00-0x02 |
X |
X |
X |
0b00/0b01/0b10 |
此處,標志位中TopicIdType決定了SUBSCRIBE消息中TopicId/TopicName字段具體填充值:預定義topic id,或短小兩個字符表示主題(topic name),或直接填寫主題。
SUBACK
網關->客戶端,訂閱處理情況的確認回執,接受訂閱或出于其它原因拒絕之。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x08 |
1 |
MsgType |
0x13 |
2 |
Flags |
標志位 |
3-4 |
TopicId |
網關接受其注冊,此處對應具體指派的TopicId |
5-6 |
MsgId |
SUBSCRIBE消息中對應MsgId值 |
7 |
ReturnCode |
0x00被接受,其它值被拒絕 |
標識位具體如下:
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
X |
0x00-0x02 |
X |
X |
X |
X |
SUBACK消息標志位中QoS為網關根據實際情況授權后的QoS具體值,這也應該是客戶端需要知道并處理的。
UNSUBSCRIBE
UNSUBSCRIBE用于客戶端取消訂閱某個主題的消息。
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x14 |
2 |
Flags |
標志位 |
3-4 |
MsgId |
用于確定對應的退訂確認UNSUBACK消息 |
5-N |
TopicId/TopicName |
具體需要根據Flags標志位中TopicIdType進行填充 |
標識位具體如下:
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
X |
X |
X |
X |
X |
0b00/0b01/0b10 |
UNSUBSCRIBE消息標志位中唯一可用屬性TopicIdType決定了UNSUBSCRIBE消息中TopicId/TopicName字段具體填充值。
UNSUBACK
網關->客戶端,取消訂閱處理情況的確認回執,很簡單,4個字節表示。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x04 |
1 |
MsgType |
0x15 |
2-3 |
MsgId |
UNSUBSCRIBE消息中對應MsgId值 |
PINGREQ
和MQTT協議中的PINGREQ一致,存活檢測。
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x16 |
2-N |
ClientId |
可選項,表示客戶端休眠狀態轉換為喚醒狀態用于檢查網關是否為其緩存消息 |
PINGRESP
接受PINGREQ消息的一方,如網關響應PINGRESP消息表示自己現在運行OK。
另外一個意圖,若喚醒狀態客戶端發送PINGREQ消息之后,直接收到PINGRESP消息,表示網關當前暫時沒有為其緩存的消息可供發送。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x02 |
1 |
MsgType |
0x17 |
很簡單,兩個字節表示足矣。
DISCONNECT
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x18 |
2-3 |
Duration |
可選項,表示客戶端即將進入睡眠狀態的持續時間值 |
- 客戶端->網關,客戶端主動關閉當前連接,網關響應確認消息。只有表示自己進入睡眠狀態的客戶端,才會在DISCONNECT消息中附加Duration持續字段。
- 網關->客戶端,網關由于異常主動通知客戶端關閉兩者之間連接,客戶端接收到DISCONNECT時需要發送CONNECT消息到網關,重試重新建立連接。沒有Duration字段填充。
網關接收到要進入休眠狀態的客戶端發送的包含有Duration字段DISCONNECT消息時,可以直接返回2個字節的(不能包含有Duration字段)DISCONNECT消息以示確認。
WILLTOPICUPD
客戶端發送請求網關更新其遺囑主題。
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x1A |
2 |
Flags |
標志位 |
3-N |
WillTopic |
用于更新的遺囑主題 |
標識位具體如下:
DUP |
QoS |
Retain |
Will |
CleanSession |
TopicIdType |
bit 7 |
6,5 |
4 |
3 |
2 |
1,0 |
X |
0x00-0x02 |
0/1 |
X |
X |
X |
協議規定只有兩個字節空WILLTOPICUPD也是允許存在的,存在意義用于客戶端請求網關刪除已保存的遺囑主題和遺囑消息等。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x02 |
1 |
MsgType |
0x1A |
WILLTOPICRESP
WILLTOPICRESP為網關收到WILLTOPICUPD后作出的應答消息。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x03 |
1 |
MsgType |
0x1B |
2 |
ReturnCode |
0x00被接受,其它值被拒絕 |
WILLMSGUPD
字節索引 |
表示內容 |
說明 |
0 |
Length |
動態計算 |
1 |
MsgType |
0x1C |
2-N |
WillMsg |
用于更新的遺囑消息 |
客戶端->網關,確認更新的遺囑消息。
WILLMSGRESP
WILLMSGRESP為網關收到WILLMSGUPD后作出的應答消息。
字節索引 |
表示內容 |
說明 |
0 |
Length |
0x03 |
1 |
MsgType |
0x1D |
2 |
ReturnCode |
0x00被接受,其它值被拒絕 |
轉發封裝
在MQTT-SN架構圖中,MQTT-SN Forwarder轉發器適用于客戶端無法直接訪問網關或當前傳感器網絡區域中不存在網關時,轉發器作用就體現出來了:
- 接收MQTT-SN客戶端消息封裝后轉發給上游網關
- 解封上游網關所發送消息,直接發送給對應客戶端
轉發器作用于消息的封裝轉發,解封發送,針對消息不做修改。
轉發器對MQTT-SN消息封裝格式:
字節索引 |
表示內容 |
說明 |
0 |
Length |
十進制表示長度就是N |
1 |
MsgType |
0xFE |
2 |
Ctrl |
包含網關和轉發器之間的控制交換信息,主要是前兩位包含了半徑范圍 |
3-N |
Wireless Node Id |
標識所發目的或需要接收封裝消息的無線節點 |
N+1-M |
MQTT-SN message |
一個MQTT-SN消息消息 |
無線節點Id(Wireless Node Id):
- 轉發器->網關,無線節點Id為轉發器所在的無線節點Id,便于告知網關轉發器位置
- 網關->轉發器,無線節點Id為網關的無線節點Id
控制交換字段Ctrl,單個字節,位表示含義:
小結
MQTT-SN 1.2規范中所定義消息格式介紹完畢,下一篇將對MQTT-SN主要流程功、能進行闡述。