MQTT-SN协议乱翻之消息格式
前言
紧接着上篇初步介绍,本文为第二篇,主要梳理MQTT-SN 1.2协议中定义的消息格式。
通用消息格式
| 消息头 | 其它可变部分 |
|---|---|
| 2/4字节表示 | N字节组成 |
消息头部
| 长度 | 消息类型 |
|---|---|
| 1或3个字节 | 1个字节 |
- 长度要么是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 | 保留,没有使用到 |
具体消息格式说明
网关周期性会对当前网络下所有客户端、节点进行广播,用于客户端发现可用网关。
| 字节索引 | 表示内容 | 说明 |
|---|---|---|
| 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 |
- 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,单个字节,位表示含义:
| bit 7,2 | 1,0 |
|---|---|
| X | 0x00-0x03 |
小结
MQTT-SN 1.2规范中所定义消息格式介绍完毕,下一篇将对MQTT-SN主要流程功、能进行阐述。
原文 http://www.blogjava.net/yongboy/archive/2015/01/08/422142.html
MQTT-SN协议乱翻之消息格式的更多相关文章
- MQTT-SN协议乱翻之功能描述
前言 紧接上文,这是第三篇,主要是对MQTT-SN 1.2协议进行总体性功能描述. 嗯,这一部分可以结合着MQTT协议对比着来看. 网关的广播和发现 网关只能在成功连接到MQTT Server之后,才 ...
- 详解FIX协议的原理、消息格式及配置开发
一.定义 FIX协议是由国际FIX协会组织提供的一个开放式协议,目的是推动国际贸易电子化的进程,在各类参与者之间,包括投资经理.经纪人,买方.卖方建立起实时的电子化通讯协议.FIX协议的目标是把各类证 ...
- 网络协议之:WebSocket的消息格式
目录 简介 WebSocket的握手流程 webSocket的消息格式 Extensions和Subprotocols 总结 简介 我们知道WebSocket是建立在TCP协议基础上的一种网络协议,用 ...
- MQTT-SN协议乱翻之小结篇
前言 这里简单做一些小结和对比,针对前面的协议翻译部分,一阶段的学习完结. MQTT-SN VS MQTT MQTT-SN基于MQTT原有语义,但做了很多的调整.比如: 一个CONNECT消息被拆分为 ...
- MQTT-SN协议乱翻之简要介绍
前言 这一段时间在翻看MQTT-SN的协议,对针对不依赖于TCP传输的MQTT协议十分感兴趣,总是再想着这货到底是怎么定义的.一系列文章皆有MQTT-SN 1.2协议所拼装组成,原文档地址: MQTT ...
- MQTT-SN协议乱翻之实现要点
前言 本篇是MQTT-SN 1.2协议最后一篇翻译了,主要涉及实现要点,很简短. 需要支持QoS 值为 -1 QoS虽默认设置有0,1,2三个值,但还有一种情况其值为-1.来自客户端的PUBLISH消 ...
- CORBA GIOP消息格式学习
想要深入理解ORB的工作过程与原理,学习与了解GIOP消息格式必不可少.我们知道GIOP是独立于具体通信的更高级别的抽象,因此这里针对GIOP在TCP/IP上的实现IIOP协议进行学习与分析(IIOP ...
- Kafka的消息格式
Commit Log Kafka储存消息的文件被它叫做log,按照Kafka文档的说法是: Each partition is an ordered, immutable sequence of me ...
- 物联网时代-跟着Thingsboard学IOT架构-MQTT设备协议
Thingsboard的MQTT设备协议 thingsboard官网: https://thingsboard.io/ thingsboard GitHub: https://github.com/t ...
随机推荐
- C语言 · 字符串对比
问题描述 给定两个仅由大写字母或小写字母组成的字符串(长度介于1到10之间),它们之间的关系是以下4中情况之一: 1:两个字符串长度不等.比如 Beijing 和 Hebei 2:两个字符串不仅长度相 ...
- drop有default constraint的column
有时候我们在drop column的时候,会遇到一些default constraints而不能drop,如果我们已经知道constraint name,则可以用下面的语句先把constraint r ...
- 关于pthread_cond_wait使用while循环判断的理解
在Stevens的<Unix 环境高级编程>中第11章线程关于pthread_cond_wait的介绍中有一个生产者-消费者的例子P311,在进入pthread_cond_wait前使用w ...
- Linux进程同步机制
为了能够有效的控制多个进程之间的沟通过程,保证沟通过程的有序和和谐,OS必须提供一定的同步机制保证进程之间不会自说自话而是有效的协同工作.比如在共享内存的通信方式中,两个或者多个进程都要对共享的内存进 ...
- 百万级PHP网站架构工具箱
在了解过世界最大的PHP站点,Facebook的后台技术后,今天我们来了解一个百万级PHP站点的网站架构:Poppen.de.Poppen.de是德国的一个社交网站,相对Facebook.Flickr ...
- 用实现ajax读博客rss示例代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...
- ZooKeeper源码分析:Quorum请求的整个流程(转)
Quorum请求是转发给Leader处理,并且需要得一个Follower Quorum确认的请求.这些请求包括: 1)znode的写操作(OpCode.create,OpCode.delete,OpC ...
- github 远程仓库操作
工作中需要在github上保存项目,一个仓库中有多个分支,进行一些实验,方便后面操作. 参考链接 http://rogerdudler.github.io/git-guide/index.zh.htm ...
- 节日(CCF试题)
试题编号: 201503-3试题名称: 节日时间限制: 1.0s内存限制: 256.0MB问题描述 有一类节日的日期并不是固定的,而是以“a月的第b个星期c”的形式定下来的,比 ...
- Bash 脚本 getopts为什么最后一个參数取不到
看以下的Bash脚本: #!/bin/bash interval=0 count=0 pid="" while getopts "p:d:n" arg do c ...