概述
这是机器未来的第28篇文章
原文首发地址:http://t.csdn.cn/9Feq3
# 1. 概述
MQTT 是客户端服务器发布/订阅消息传输协议。它重量轻、开放、简单,并且设计易于实施。这些特性使其非常适合在许多情况下使用,包括受限制的环境,例如机器对机器 (M2M) 和物联网 (IoT) 环境中的通信,其中需要小代码足迹和/或网络带宽非常宝贵。
该协议通过 TCP/IP 或其他提供有序、无损、双向连接的网络协议运行。其特点包括:
- 使用发布/订阅消息模式,提供一对多的消息分发和应用程序的解耦。
- 与有效负载内容无关的消息传输。
- 消息传递的三种服务质量:
- “最多一次”,根据操作环境的最大努力传递消息。可能会发生消息丢失。例如,此级别可用于环境传感器数据,其中单个读数是否丢失并不重要,因为下一个读数将很快发布。
- “至少一次”,确保消息到达但可能出现重复。
- “Exactly once”,保证消息只到达一次。例如,此级别可用于重复或丢失消息可能导致应用不正确费用的计费系统。
- 最小化传输开销和协议交换以减少网络流量。
- 发生异常断开时通知相关方的机制。
2. 数据编码规则
2.1 位
字节中的位标记为 7 到 0。第 7 位是最高有效位,最低有效位分配给第 0 位。
2.2 整数数据值
整数数据值是大端顺序的 16 位:高位字节在低位字节之前。这意味着 16 位字在网络上显示为最高有效字节 (MSB),然后是最低有效字节 (LSB)。
举例: 16位整数1的编码值为0x00 0x01,高位0x00在前,低位0x01在后。
2.3 UTF-8 编码字符串
-
UTF-8编码字符串的规则如下:
前面2个字节表示长度,长度的编码规则符合2.2的定义,UTF-8编码字符串符合 RFC3629的定义。
编码规则:
在 UTF-8 中,U+0000…U+10FFFF 范围内的字符(UTF-16 可访问范围)使用 1 到 4 个八位字节的序列进行编码。- 只有一个“序列”的八位字节将高位设置为 0,其余 7 位用于对字符编号进行编码。
- 在一个n 个八位字节的序列,n>1,初始八位位组有 n 个高阶位设置为 1,然后是位设置为 0。其余位该八位字节包含要成为的字符数中的位编码。随后八位字节都将高阶位设置为1 和后面的位设置为 0,每个保留 6 位包含来自要编码的字符的位。
特别注意:收到以下范围内的编码数据,服务端/客户端必须关闭链接。
- UTF-8 编码的字符串不得包括 U+D800 和 U+DFFF 之间的编码
- UTF-8 编码的字符串不得包含空字符 U+0000 的编码
- U+0001…U+001F 控制字符
- U+007F…U+009F 控制字符
- Unicode 规范中定义的代码点[ Unicode ]是非字符(例如 U+0FFFF)
示例:字母 A 后跟代码点 U+2A6D4的表示如下
编码后的UTF-8数据:
0x41 0xF0 0xAA 0x9B 0x94
转换为二进制---->
0100 0001 1111 0000 1010 1010 1001 1011 1001 0100
(0x41) (0xF0) (0xAA) (0x9B) (0x94)
Utf-8编码解析---->
0100 0001
11110
‾
underline{1111 0}
11110 000
10
‾
underline{10}
10 10 1010
10
‾
underline{10}
10 01 1011
10
‾
underline{10}
10 01 0100
解析规则:
根据UTF-8字符串编码规则:
0x41:字节的高位为0,则剩余7位为有效数据位,其值即为原值0x41
0xF0:字节的高4位为1111,说明UTF-8编码字符串的长度为4字节,11110为编码前缀,后续的000为有效数据位,后续的字节10为编码前缀,后6位为有效数据位,则其值为0 0010 1010 0110 1101 0100,其16进制表示为0x2A6D4
综上,原始值为0x2A6D4
- 协议中使用到UTF-8字符串的协议为
- CONNECT协议的ClientID、遗嘱topic、username、
- PUBLISH的Topic名称
- UNSUBSCRIBE的主题过滤器
这些字段尽可能使用单字节编码UTF-8,便于编解码。
3. MQTT控制包格式
3.1 MQTT控制包结构
MQTT 协议通过以定义的方式交换一系列 MQTT 控制数据包来工作。本节介绍这些数据包的格式。一个 MQTT 控制包最多由三个部分组成,始终按以下顺序排列,如图所示。
3.1.1 固定头
每个 MQTT 控制包都包含一个固定的标头。图 2.2 - 固定头格式说明了固定头格式。
3.1.1 MQTT控制包类型
位置:字节 1,位 7-4。
表示为 4 位无符号值,这些值在表 2.1 - 控制数据包类型中列出。
3.1.1.2 标志
目前仅PUBLISH支持标志的配置,其余均为保留将来使用。
DUP
如果 DUP 标志设置为 0,则表明这是客户端或服务器第一次尝试发送此 MQTT PUBLISH 数据包。如果 DUP 标志设置为 1,则表明这可能是先前尝试发送数据包的重新传递。
当客户端或服务器尝试重新传递 PUBLISH 数据包[MQTT-3.3.1.-1]时,必须将 DUP 标志设置为 1 。对于所有 QoS 0 消息[MQTT-3.3.1-2] ,必须将 DUP 标志设置为 0 。
-
QoS
-
RETAIN
如果 RETAIN 标志设置为 1,在客户端发送给服务器的 PUBLISH 数据包中,服务器必须存储应用程序消息及其 QoS,以便可以将其传递给订阅匹配其主题名称的未来订阅者
3.1.1.3 剩余长度
位置:从字节 2 开始。
剩余长度是当前数据包中剩余的字节数,包括可变标头和有效负载中的数据。剩余长度不包括用于编码剩余长度的字节。
Remaining Length 使用可变长度编码方案进行编码,该方案使用单个字节表示最大为 127 的值。较大的值按如下方式处理。每个字节的最低七位对数据进行编码,最高位用于表示表示中有后续字节。因此,每个字节编码 128 个值和一个“连续位”。剩余长度字段中的最大字节数为 4。
编码规则C语言实现:
do {
code = X % 128;
X = X / 128;
if (X > 0)
{
code = code | 128;
}
else
{
code = code;
}
} while (X >0);
举例说明:十进制数 321编码后的十六进制序列为0xC1 0x02
计算过程:
X = 321
code = X % 128 = 65
X = X / 128 = 321 / 128 = 2
Byte1:code | 128 = 65 | 128 = 0xC1
code = X % 128 = 2 % 128 = 2
Byte2:code = 2
可支持的剩余长度范围如图:
3.1.2 可变数据头
某些类型的 MQTT 控制数据包包含可变标头组件。它位于固定报头和有效负载之间。可变报头的内容因数据包类型而异。可变报头的数据包标识符字段在几种数据包类型中很常见。
许多控制数据包类型的可变报头组件包括一个 2 字节的数据包标识符字段。这些控制数据包是 PUBLISH(其中 QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK。
订阅、取消订阅和发布(在 QoS > 0 的情况下)控制数据包必须包含非零的 16 位数据包标识符 [MQTT-2.3.1-1]。
- 每次客户端发送这些类型之一的新数据包时,它必须为其分配一个当前未使用的数据包标识符 [MQTT-2.3.1-2]。
- 如果客户端重新发送一个特定的控制包,那么它必须在该包的后续重新发送中使用相同的包标识符。在客户端处理完相应的确认数据包后,数据包标识符就可以重新使用了。
- 在 QoS 1 PUBLISH 的情况下,这是相应的 PUBACK;在 QoS 2 的情况下,它是 PUBCOMP。
- 对于 SUBSCRIBE 或 UNSUBSCRIBE,它是对应的 SUBACK 或 UNSUBACK [MQTT-2.3.1-3]。
- 当服务器发送具有 QoS > 0 [MQTT-2.3.1-4]的 PUBLISH 时,相同的条件适用于服务器。
如果 PUBLISH 数据包的 QoS 值设置为 0 [MQTT-2.3.1-5] ,则 PUBLISH 数据包不得包含数据包标识符。
PUBACK、PUBREC 或 PUBREL 数据包必须包含与最初发送的 PUBLISH 数据包相同的数据包标识符 [MQTT-2.3.1-6]。同样,SUBACK 和 UNSUBACK 必须包含分别在相应的 SUBSCRIBE 和 UNSUBSCRIBE 数据包中使用的数据包标识符 [MQTT-2.3.1-7]。
客户端和服务器相互独立地分配数据包标识符。因此,客户端服务器对可以使用相同的数据包标识符参与并发消息交换。
3.1.3 有效载荷
一些 MQTT 控制数据包包含一个有效负载作为数据包的最后部分,如第 3 章所述。在 PUBLISH 数据包的情况下,这是应用程序消息。表 2.6 - 包含有效负载的控制包列出了需要有效负载的控制包。
至此,MQTT总体协议框架大致梳理了一遍,后续再梳理具体的协议命令。
参考链接:
- MQTT Version 3.1.1 Plus Errata 01
《MQTT从入门到提高系列》快速导航:
- 【MQTT从入门到提高系列 | 01】从0到1快速搭建MQTT测试环境
- 【MQTT从入门到提高系列 | 02】MQTT3.1.1TLS加密传输
- 【MQTT从入门到提高系列 | 03】一文掌握MQTT3.1.1协议框架
- 【MQTT从入门到提高系列 | 04】MQTT应用协议之CONNECT
- 【MQTT从入门到提高系列 | 05】MQTT3.1.1之PUBLISH发布工作流
- 【MQTT从入门到提高系列 | 06】MQTT3.1.1之SUBSCRIBE订阅工作流
- 【MQTT从入门到提高系列 | 07】MQTT3.1.1之链路保活及断开
- 【MQTT从入门到提高系列 | 08】MQTT3.1.1主题Topic详解
- 【MQTT从入门到提高系列 | 09】WireShark抓包分析MQTT报文
写在末尾:
- 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!
- 专栏简介:从0到1掌握MQTT分布式协议。
- 面向人群:零基础编程爱好者
- 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待
- Python零基础快速入门系列
- 快速入门Python数据科学系列
- 人工智能开发环境搭建系列
- 机器学习系列
- 物体检测快速入门系列
- 自动驾驶物体检测系列
- …
最后
以上就是怕孤独百合为你收集整理的【MQTT从入门到提高系列 | 03】一文掌握MQTT3.1.1协议框架2. 数据编码规则3. MQTT控制包格式的全部内容,希望文章能够帮你解决【MQTT从入门到提高系列 | 03】一文掌握MQTT3.1.1协议框架2. 数据编码规则3. MQTT控制包格式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复