打印
[技术讨论]

百问MQTT协议分析 - MQTT简述及协议报文格式组成

[复制链接]
548|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
神棍地海棠|  楼主 | 2024-12-13 09:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
## 16.1 mqtt协议介绍

### 16.1.1 概述

​                MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境(IoT)。

### 16.1.2 特点

a)   开放消息协议,简单易实现

b)   发布订阅模式,一对多消息发布

c)   基于TCP/IP网络连接

d)   1字节固定报头,2字节心跳报文,报文结构紧凑

e)   消息QoS支持,可靠传输保证

### 16.1.3 应用

​                MQTT协议广泛应用于物联网、移动互联网、智能硬件、车联网、电力能源等领域。

a)   物联网M2M通信,物联网大数据采集

b)   Android消息推送,WEB消息推送

c)   移动即时消息,例如Facebook Messenger

d)   智能硬件、智能家具、智能电器

e)   车联网通信,电动车站桩采集

f)    智慧城市、远程医疗、远程教育

g)   电力、石油与能源等行业市场

## 16.2 mqtt协议报文格式组成

### 16.2.1 mqtt控制报文结构

MQTT 协议通过交换预定义的 MQTT 控制报文来通信。 这一节描述这些报文的格式。MQTT 控制报文由三部分组成,如下图:

![图2.1 mqtt报文组成]()


### 16.2.2 mqtt固定报头

​                每个 MQTT 控制报文都包含一个固定报头, 固定报头的格式如下图:

![图2.2 mqtt固定报头]()


### 16.2.3 mqtt控制报文类型

​                位置: 第 1 个字节, 二进制位 7-4,表示为 4 位无符号值。

​                MQTT 控制报文的类型:如下表:

| 名字            | 值   | 报文流动方向   | 描述                                |
| --------------- | ---- | -------------- | ----------------------------------- |
| **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   | 禁止           | 保留                                |

### 16.2.4 标记

​                固定报头第 1 个字节的剩余的 4 位 [3-0]包含每个 MQTT 控制报文类型特定的标志 。标记位说明如下表所示:

| 控制报文        | 固定报头标志        | Bit 3 | Bit 2 | Bit 1 | Bit 0   |
| --------------- | ------------------- | ----- | ----- | ----- | ------- |
| **CONNECT**     | Reserved            | 0     | 0     | 0     | 0       |
| **CONNACK**     | Reserved            | 0     | 0     | 0     | 0       |
| **PUBLISH**     | Used  in MQTT 3.1.1 | DUP1  | QoS2  | QoS2  | RETAIN3 |
| **PUBACK**      | Reserved            | 0     | 0     | 0     | 0       |
| **PUBREC**      | Reserved            | 0     | 0     | 0     | 0       |
| **PUBREL**      | Reserved            | 0     | 0     | 1     | 0       |
| **PUBCOMP**     | Reserved            | 0     | 0     | 0     | 0       |
| **SUBSCRIBE**   | Reserved            | 0     | 0     | 1     | 0       |
| **SUBACK**      | Reserved            | 0     | 0     | 0     | 0       |
| **UNSUBSCRIBE** | Reserved            | 0     | 0     | 1     | 0       |
| **UNSUBACK**    | Reserved            | 0     | 0     | 0     | 0       |
| **PINGREQ**     | Reserved            | 0     | 0     | 0     | 0       |
| **PINGRESP**    | Reserved            | 0     | 0     | 0     | 0       |
| **DISCONNECT**  | Reserved            | 0     | 0     | 0     | 0       |

DUP1 =控制报文的重复分发标志
QoS2 = PUBLISH 报文的服务质量等级
RETAIN3 = PUBLISH 报文的保留标志

### 16.2.5 剩余长度

​                位置:从第二个字节开始。剩余长度( Remaining Length) 表示当前报文剩余部分的字节数, 包括可变报头和负载的数据。 剩余长度不包括用于编码剩余长度字段本身的字节数。

![图2.3 剩余长度包含的报文范围]()


​                剩余长度字段使用一个变长度编码方案, 对小于 128 的值它使用单字节编码。 更大的值按下面的方式处理。低 7 位有效位用于编码数据,最高有效位用于指示是否有更多的字节。 因此每个字节可以编码 128 个数值和一个延续位( continuation bit) 。 剩余长度字段最大 4 个字节。

​                例如, 十进制数 64 会被编码为一个字节, 数值是 64, 十六进制表示为 0x40,。十进制数字321(=65+2*128)被编码为两个字节, 最低有效位在前。 第一个字节是 65+128=193。 注意最高位为
1 表示后面至少还有一个字节。 第二个字节是 2。

#### 16.2.5.1 示例

```c
123456  = 964 x 128 + 64

964 = 7x128 + 68

7 < 128

也就是123456 = (7 x 128 + 68)x128 + 64

展开:64 + 68 x128 + 7x128x128

第一字节:64 | 0x80 = x (0x80=0x1000 0000或上最高位表示是否还有更多的字节)

第二字节:68 | 0x80 = y (0x80=0x1000 0000或上最高位表示是否还有更多的字节)

第三字节:7=z

c语言表示:unsigned char len_byte[4] = { 64 | 128 , 68 | 128,  7  , 0 }

反过来,如果要算出123456

x-128 + (y-128)*128 + z x 128 x 128
```

把剩余长度转换成字节表示:

![]()

把字节转换成剩余长度表示:

![]()

### 16.2.6 可变报头

​                某些 MQTT 控制报文包含一个可变报头部分。 它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。报文标识符是可变报头一种,可变报头的报文标识符( Packet Identifier) 字段存在于在多个类型的报文里。

报文标识符类型如下图:

![图2.4 报文标识符]()


​                很多控制报文的可变报头部分包含一个两字节的报文标识符字段。 这些报文是 PUBLISH( QoS>0 时) ,PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCIBE,UNSUBACK,如下表所示:

| **控制报文**    | **报文标识符字段**  |
| --------------- | ------------------- |
| **CONNECT**     | 不需要              |
| **CONNACK**     | 不需要              |
| **PUBLISH**     | 需要(如果QoS > 0) |
| **PUBACK**      | 需要                |
| **PUBREC**      | 需要                |
| **PUBREL**      | 需要                |
| **PUBCOMP**     | 需要                |
| **SUBSCRIBE**   | 需要                |
| **SUBACK**      | 需要                |
| **UNSUBSCRIBE** | 需要                |
| **UNSUBACK**    | 需要                |
| **PINGREQ**     | 不需要              |
| **PINGRESP**    | 不需要              |
| **DISCONNECT**  | 不需要              |

​                客户端和服务端彼此独立地分配报文标识符。 因此,客户端服务端组合使用相同的报文标识符可以实现并发的消息交换。

​                例如,当client发送一个packet Identifier =0x1234的报文给server时,server的回复报文packet identifier 必须是0x1234,Packet identifier 从1开始递增,到达65535时,又从1开始计算。

![图2.5 需要 Packet Identifier  的报文类型交互示意图]()


### 16.2.7 有效载荷

​                某些 MQTT 控制报文在报文的最后部分包含一个有效载荷,带有有效载荷报文类型如下表所示:

| **控制报文**    | **有效载荷** |
| --------------- | ------------ |
| **CONNECT**     | 需要         |
| **CONNACK**     | 不需要       |
| **PUBLISH**     | 可选         |
| **PUBACK**      | 不需要       |
| **PUBREC**      | 不需要       |
| **PUBREL**      | 不需要       |
| **PUBCOMP**     | 不需要       |
| **SUBSCRIBE**   | 需要         |
| **SUBACK**      | 需要         |
| **UNSUBSCRIBE** | 需要         |
| **UNSUBACK**    | 不需要       |
| **PINGREQ**     | 不需要       |
| **PINGRESP**    | 不需要       |
| **DISCONNECT**  | 不需要       |


使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

282

主题

290

帖子

1

粉丝