前言
紧接着上篇初步介绍,本文为第二篇,主要梳理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主要流程功、能进行阐述。