1. MQTT协议简介
1.1 MQTT协议介绍
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。
MQTT最大优点在于,用极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
1.2 MQTT特点
MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。
这是一种消息传递模式,消息不是直接从发送器发送到接收器(即点对点),而是由MQTT server(或称为 MQTT Broker)分发的。
发布/订阅模式图解:
Qos(服务质量)
服务质量是 MQTT 的一个重要特性。当我们使用 TCP/IP 时,连接已经在一定程度上受到保护。但是在无线网络中,中断和干扰很频繁,MQTT 在这里帮助避免信息丢失及其服务质量水平。这些级别在发布时使用。如果客户端发布到 MQTT 服务器,则客户端将是发送者,MQTT 服务器将是接收者。当MQTT服务器向客户端发布消息时,服务器是发送者,客户端是接收者。
Qos 0
这一级别会发生消息丢失或重复,消息发布依赖于底层TCP/IP网络。
QoS 1
承诺消息将至少传送一次给订阅者。
QoS 2
使用 QoS 2,我们保证消息仅传送到目的地一次。为此,带有唯一消息 ID 的消息会存储两次,首先来自发送者,然后是接收者。QoS 级别 2 在网络中具有最高的开销,因为在发送方和接收方之间需要两个流。
2. MQTT控制报文格式
2.1 MQTT控制报文格式
MQTT控制报文结构:
Fixed header 固定报头,所有控制报文都包含 |
Variable header 可变报头,部分控制报文包含 |
Payload 有效载荷,部分控制报文包含 |
2.2 固定报头
固定报头结构:
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Byte1 | MQTT控制报文的类型 | 用于指定控制报文类型的标志位 | ||||||
Byte2 | 剩余长度 |
2.2.1MQTT控制报文的类型
名字 | 值 | 报文流动方向 | 描述 |
Reserved | 0 | 禁止 | 保留 |
CONNECT | 1 | 客户端到服务器 | 客户端请求连接服务器 |
CONNACK | 2 | 服务器到客户端 | 连接报文确认 |
PUBLISH | 3 | 两个方向动允许 | 发布消息 |
PUBACK | 4 | 两个方向都允许 | QoS 1消息发布收到确认 |
PUBREC | 5 | 两个方向都允许 | 发布收到 |
PUBREL | 6 | 两个方向都允许 | 发布释放 |
PUBCOMP | 7 | 两个方向都允许 | QoS 2消息发布完成 |
SUBSCRIBE | 8 | 客户端到服务端 | 客户端到服务端 |
SUBACK | 9 | 服务器到客户端 | 订阅请求报文确认 |
UNSUBSCRIBE | 10 | 客户端到服务端 | 客户端取消订阅请求 |
UNSUBACK | 11 | 服务器到客户端 | 取消订阅报文确认 |
PINGREQ | 12 | 客户端到服务端 | 心跳请求 |
PINGRESP | 13 | 服务器到客户端 | 心跳响应 |
DISCONNECT | 14 | 客户端到服务端 | 客户端断开连接 |
Reserved | 15 | 禁止 | 保留 |
2.2.2标志
2.2.3 剩余长度
剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。
剩余长度字段使用一个变长度编码方案,对小于128的值它使用单字节编码。更大的值按下面的方式处理。低7位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码128个数值和一个延续位(continuation bit)。剩余长度字段最大4个字节。
2.3 可变报头
某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
2.4 有效载荷
3. MQTT控制报文
3.1 CONNECT – 连接服务器
数据报文说明:
- 表格最左边数据位,表示数据的第7位,最右端表示第0位
- 第1Bit:前4位,用来决定命令类型
- 后4位,保留
- 第2Bit:剩余长度,计算方法-放最后
- 剩余长度 = 可变报头长度 + 有效载荷
- 第3Bit:可变报头的开始
1Bit | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
2Bit | 剩余长度 | |||||||
3Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4Bit | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
5Bit | ‘M’ | |||||||
6Bit | ‘Q’ | |||||||
7Bit | ‘T’ | |||||||
8Bit | ‘T’ | |||||||
9Bit | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
10Bit | x | x | x | x | x | x | x | x |
11Bit | 保持连接Keep Alive MSB | |||||||
12Bit | 保持连接Keep Alive LSB |
第10Bit:
- 第0位:保留位
- 第1位:清理会话
- 为0时,
- 为1时,客户端和服务端必须丢弃之前的任何会话并开始一个新会话
- 第2位:遗嘱标志
- 为1时,设置遗嘱
- 第3/4位:发布遗嘱使用的服务等级
- 如果遗嘱标志位为0,3/4必须为0
- 如果遗嘱标志位为1,Qos可等于0, 1, 2。
- 第5位:遗嘱保留
- 第6位:用户名,有用户名,标志位为1,否则为0
- 第7位:密码,有密码,标志位为1,否则为0
3.2 CONNACK – 确认连接请求
数据报文说明:
- 第2Bit:表示可变长为2Bit
- 第3Bit:第0位是当前会话标志位
- 如果服务端收到清理会话标志为 1 的连接,除了将 CONNACK 报文中的返回码设置为 0之外,还必须将 CONNACK 报文中的当前会话设置标志为 0
- 第4Bit:连接返回码
1Bit | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
3Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | x |
4Bit | X | X | X | X | X | X | X | X |
连接返回码说明:
值 | 返回码响应 | 描述 |
0 | 0x00连接已接受 | 连接已被服务端接受 |
1 | 0x01连接已拒绝,不支持的协议版本 | 服务端不支持客户端请求的MQTT协议级别 |
2 | 0x02连接已拒绝,不合格的客户端标识符 | 客户端标识符是正确的UTF-8编码,但服务端不允许使用 |
3 | 0x03连接已拒绝,服务端不可用 | 网络连接已建立,但MQTT服务不可用 |
4 | 0x04连接已拒绝,无效的用户名或密码 | 用户名或密码的数据格式无效 |
3.3 PUBLISH – 发布消息
数据报文说明:
- 1Bit:第3位:重发标志位
- 标志位为0,第一次发送PUBLISH报文
- 标志位为1,表示可能是之前报文的重发
- 第1,2位,服务质量等级
Qos值 | Bit2 | Bit1 | 描述 |
0 | 0 | 0 | 最多发一次 |
1 | 0 | 1 | 至少分发一次 |
2 | 1 | 0 | 只分发一次 |
- | 1 | 1 | 保留位 |
第0位,保留标志
发布消息报文,以主题为a/b,报文表标识符为10,举例
1Bit | 0 | 0 | 1 | 1 | x | x | x | x |
2Bit | 剩余长度 | |||||||
3Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
5Bit | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
6Bit | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 1 |
7Bit | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 |
8Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9Bit | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
10Bit | 有效载荷 |
3.4 PUBLISH – 发布确认
1Bit | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
3Bit | 报文标识符MSB | |||||||
4Bit | 报文标识符LSB |
3.5 PUBREC – 发布收到(QoS 2,第一步)
1Bit | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
3Bit | 报文标识符 | |||||||
4Bit | 报文标识符 |
3.6 PUBREL – 发布释放(QoS 2,第二步)
1Bit | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
3Bit | 报文标识符 | |||||||
4Bit | 报文标识符 |
3.7 PUBCOMP – 发布完成(QoS 2,第三步)
1Bit | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
3Bit | 报文标识符 | |||||||
4Bit | 报文标识符 |
3.8 SUBSCRIBE - 订阅主题
1Bit | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
2Bit | 剩余长度 | |||||||
3Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4Bit | 报文标识符LSB | |||||||
5Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
6Bit | 主题字符串 | |||||||
N+1Bit | 0 | 0 | 0 | 0 | 0 | 0 | 服务质量等级 |
3.9 SUBACK – 订阅确认
1Bit | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
2Bit | 剩余长度 | |||||||
3Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
4Bit | 报文标识符LSB | |||||||
5Bit | X | 0 | 0 | 0 | 0 | 0 | X | X |
5Bit是返回码,允许的返回码值:
- 0x00 - 最大 QoS 0
- 0x01 - 成功 – 最大 QoS 1
- 0x02 - 成功 – 最大 QoS 2
- 0x80 - Failure 失败
3.10 UNSUBSCRIBE –取消订阅主题
1Bit | 1 | 0 | 1 | 0 | 0 | 0 | 2 | 0 |
2Bit | 剩余长度 | |||||||
3Bit | 报文标识符MSB | |||||||
4Bit | 报文标识符LSB | |||||||
5Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
6Bit | 推测是长度 | |||||||
7Bit | 主题字符串的开始 |
3.11 UNSUBACK – 取消订阅确认
1Bit | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
3Bit | 报文标识MSB | |||||||
4Bit | 报文标识LSB |
3.12 PINGREQ – 心跳请求
1Bit | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3.13 PINGRESP – 心跳响应
1Bit | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
3.14 DISCONNECT –断开连接
1Bit | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
2Bit | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |