MQTT协议总结 报文基础结构 报文组成 是否可选 固定报文头 固定存在 可变报文头 可选 有效荷载 可选
固定报文头 每个MQTT报文都包含固定报文头
固定报文头 字节索引 高低位 作用 报文类型 1 高 命令的种类(共16种,0~15) 标志位 1 低 命令的具体行为特征 长度 2-5 全 可变高8位为0时不往下读取
可变头 包含每个报文的上下文信息,每个报文类型的可变头内容和长度都不同,后面在介绍报文的时候一起总结
荷载 用于传递报文真正的业务数据,同样每个报文类型的荷载数据各不相同,后面在介绍报文的时候一起总结
QoS Qos 分为 3个等级 0、1、2 0等级:生产者发送数据后,无需接收响应,无重传机制 1等级:生产者发送数据后,需要一次响应,有重传机制 2等级:生产者发送数据后,需要交互两次,有重传机制
报文类型整理
链接与断开 标志位序号 16进制序号 命令名称 方向 作用 1 0x1 CONNECT 客户端->服务器 发起TCP连接后的第一个报文,携带ClientID、账号密码、心跳时间 2 0x2 CONNACK 服务端->客户端 服务端对CONNECT的回应,告诉你“连上了”或“密码错误” 14 0xE DISCONNECT 双向 优雅地断开连接,通知Broker“我要下线了,别等我心跳了
CONNECT真实报文 10 1D 00 04 4D 51 54 54 04 C2 00 3C 00 04 74 65 73 74 00 05 61 64 6D 69 6E 00 04 70 61 73 73字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 10 固定头 CONNECT 长度 2 1D 固定头 剩余长度 = 29 协议名 3-8 00 04 4D 51 54 54 可变头 两字节长度 4字节“MQTT”固定标识 协议级别 9 04 可变头 用的是3.1.1 (0x04) 还是5.0 (0x05) 连接标识 10 C2 可变头 可变头控制是否带密码、是否清理会话、是否有遗嘱 保活时间 11-12 00 3C 可变头 超过多少秒没发数据,可以踢 ClinetID 13-18 00 04 74 65 73 74 有效荷载 (2字节长度 + ID)这里是test 用户名 19-25 00 05 61 64 6D 69 6E 有效荷载 (2字节长度 + 用户名)这里是admin 密码 26-30 00 04 70 61 73 73 有效荷载 (2字节长度 + 密码)这里是pass
连接标识的意义 0xC2 11 00 001 0 ││││ │││└─ Bit 0: Reserved = 0 ││││ ││└── Bit 1: Clean Session = 1 → 清理会话 ││││ │└─── Bit 2: Will Flag = 0 → 无遗嘱 ││││ └──── Bit 3: Will QoS bit0 = 0 ┐ │││└────── Bit 4: Will QoS bit1 = 0 ┘ → QoS = 0 ││└─────── Bit 5: Will Retain = 0 → 无效 │└──────── Bit 6: Password Flag = 1 → 有密码 └───────── Bit 7: User Name Flag = 1 → 有用户名
CONNACK 真实报文 20 02 01 00字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 20 固定头 CONNACK 长度 2 02 固定头 剩余长度 = 2 连接标识 3 01 可变头 连接返回码 连接返回码 4 00 可变头
连接返回码如下: 0x00 连接已接受 0x01 拒绝:不支持的协议版本 0x02 拒绝:无效的客户端标识符 0x03 拒绝:服务端不可用 0x04 拒绝:用户名或密码错误 0x05 拒绝:未授权 Session Present位 只有 Clean Session = 0(不清理会话)时,这个位才有意义。 如果 Clean Session = 1,服务端必须将此位置 0。
DISCONNECT 真实报文 E0 00字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 E0 固定头 DISCONNECT 长度 2 00 固定头 剩余长度 = 0
消息发布流转 标志位序号 16进制序号 命令名称 方向 作用 3 0x30 PUBLISH 双向 真正的消息载体。生产者发它给Broker,Broker也发它给消费者 4 0x40 PUBACK 双向 QoS 1专用。接收方说:我已收到这条消息(QoS 1),不用重发了 5 0x50 PUBREC 双向 QoS 2专用(第1步)。接收方说:我收到你的QoS 2消息了 6 0x60 PUBREL 双向 QoS 2专用(第2步)。发送方说:好的,那你把这条消息释放给消费者吧 7 0x60 PUBCOMP 双向 QoS 2专用(第3步)。接收方说:我已经处理完了,这事彻底了结
PUBLISH 真实报文(生产者向代理发送数据、代理发向消费者) 3A 11 00 0B 73 65 6E 73 6F 72 2F 74 65 6D 70 00 01 32 35 2E 36字段名称 字节范围 内容 所属部分 作用 报文类型 1(高4位) 0x3 固定头 PUBLISH 标志位 1(低4位) 0xA 固定头 DUP (重发标识)、QoS bit1、QoS bit0、Retain(保留标志) 长度 2 11 固定头 长度= 17 主题长度 3-4 00 0B 可变头 主题名长度= 11字节 主题名 5-15 73 65 6E 73 6F 72 2F 74 65 6D 70 可变头 sensor/temp 报文标识符 16-17 00 01 Packet ID (QoS>0时必须) 数据内容 18-21 32 35 2E 36 有效荷载 生产者发送的数据 26.5
PUBACK 真实报文(代理回复生产者、消费者回复代理) 只有QoS 1 需要 PUBACK
40 02 00 01字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 0x40 固定头 PUBACK 长度 2 0x02 固定头 长度=2字节 报文标识符 3-4 2 可变头 Packet ID (QoS>0时必须)
PUBREC 真实报文 只有QoS 2 需要 PUBREC
50 02 00 01字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 0x50 固定头 PUBREC 长度 2 0x02 固定头 长度=2字节 报文标识符 3-4 2 可变头 Packet ID (QoS>·1时必须)
PUBREL 真实报文 只有QoS 2 需要 PUBREL
62 02 00 01字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 0x62 固定头 PUBREL 长度 2 0x02 固定头 长度=2字节 报文标识符 3-4 2 可变头 Packet ID (QoS>·1时必须)
PUBCOMP 真实报文 只有QoS 2 需要 PUBCOMP
70 02 00 01字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 0x70 固定头 PUBCOMP 长度 2 0x02 固定头 长度=2字节 报文标识符 3-4 2 可变头 Packet ID (QoS>·1时必须)
订阅与取消订阅 标志位序号 16进制序号 命令名称 方向 作用 8 0x8 SUBSCRIBE 客户端->服务端 客户端发起订阅请求 9 0x9 SUBACK 服务端->客户端 服务端回应订阅 10 0xA UNSUBSCRIBE 客户端->服务端 客户端发起取消订阅 11 0xB UNSUBACK 服务端->客户端 服务端回应取消
SUBSCRIBE 真实报文 82 17 00 01 00 0B 73 65 6E 73 6F 72 2F 74 65 6D 70 01 00 05 63 6D 64 2F 23 00字段名称 字节范围 内容 所属部分 作用 报文类型+ 标志位 1 0x82 固定头 SUBSCRIBE 长度 2 0x17 固定头 剩余长度 = 23 包ID 3-4 00 01 可变头 Packet ID = 1 主题1长度 5-6 00 0B 有效荷载 主题长度 = 11 主题1名 7-17 73 65 6E 73 6F 72 2F 74 65 6D 70 有效荷载 “sensor/temp” 主题1的QoS等级 18 01 有效荷载 主题1的QoS等级 = 1 主题2长度 19-20 00 05 有效荷载 主题2的长度 主题2名 21-25 63 6D 64 2F 23 有效荷载 主题2名称 = cmd/# 主题2QoS等级 26 00 有效荷载 主题2的QoS等级 = 0
SUBACK真实报文 90 04 00 01 01 00字段名称 字节范围 内容 所属部分 作用 报文类型+ 标志位 1 0x90 固定头 SUBACK 长度 2 0x4 固定头 剩余长度= 4 长度 2 0x17 固定头 剩余长度 = 23 包ID 3-4 00 01 可变头 Packet ID = 1 主题1返回 5 01 有效荷载 主题1返回码:QoS 1 授予 主题2返回 6 00 有效荷载 主题1返回码:QoS 2 授予
其中主题返回有4种情况
值 含义 0x00 QoS 0 成功 0x01 QoS 1 成功 0x02 QoS 2 成功 0x80 失败(被拒绝)
UNSUBSCRIBE 真实报文 A2 0E 00 02 00 0B 73 65 6E 73 6F 72 2F 74 65 6D 70字段名称 字节范围 内容 所属部分 作用 报文类型+标志位 1 0xA2 固定头 UNSUBSCRIBE 长度 2 0x0E 固定头 剩余长度 = 14 包ID 3-4 00 02 可变头 Packet ID = 2 主题1长度 5-6 00 0B 有效荷载 主题长度 = 11 主题1名 7-17 73 65 6E 73 6F 72 2F 74 65 6D 70 有效荷载 “sensor/temp”
UNSUBACK 真实报文 B0 02 00 02字段名称 字节范围 内容 所属部分 作用 报文类型+ 标志位 1 0xB0 固定头 UNSUBACK 长度 2 0x02 固定头 剩余长度 = 2 包ID 3-4 00 02 可变头 Packet ID = 2
心跳保活 PINGREQ 真实报文(客户端->服务端) C0 00字段名称 字节范围 内容 所属部分 作用 报文类型+ 标志位 1 0xC0 固定头 PINGREQ 长度 2 0x00 固定头 剩余长度 = 0
PINGRESP (服务端->客户端) D0 00字段名称 字节范围 内容 所属部分 作用 报文类型+ 标志位 1 0xD0 固定头 PINGRESP 长度 2 0x00 固定头 剩余长度 = 0