MQTT 5.0 报文(Packets)入门指南

本文涉及的产品
性能测试 PTS,5000VUM额度
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
简介: MQTT 控制报文是 MQTT 数据传输的最小单元。MQTT 客户端和服务端通过交换控制报文来完成它们的工作,比如订阅主题和发布消息。

什么是 MQTT 控制报文?

MQTT 控制报文是 MQTT 数据传输的最小单元。MQTT 客户端和服务端通过交换控制报文来完成它们的工作,比如订阅主题和发布消息。

MQTT 目前定义了 15 种控制报文类型,如果按照功能进行分类,我们可以将这些报文分为连接、发布、订阅三个类别:

01mqttpackettypes.png

其中,CONNECT 报文用于客户端向服务端发起连接,CONNACK 报文则作为响应返回连接的结果。如果想要结束通信,或者遇到了一个必须终止连接的错误,客户端和服务端可以发送一个 DISCONNECT 报文然后关闭网络连接。

AUTH 报文是 MQTT 5.0 引入的全新的报文类型,它仅用于增强认证,为客户端和服务端提供更安全的身份验证。

PINGREQ 和 PINGRESP 报文用于连接保活和探活,客户端定期发出 PINGREQ 报文向服务端表示自己仍然活跃,然后根据 PINGRESP 报文是否及时返回判断服务端是否活跃。

PUBLISH 报文用于发布消息,余下的四个报文分别用于 QoS 1 和 2 消息的确认流程。

SUBSCRIBE 报文用于客户端向服务端发起订阅,UNSUBSCRIBE 报文则正好相反,SUBACK 和 UNSUBACK 报文分别用于返回订阅和取消订阅的结果。

MQTT 报文格式

在 MQTT 中,无论是什么类型的控制报文,它们都由固定报头、可变报头和有效载荷三个部分组成。

固定报头固定存在于所有控制报文中,而可变报头和有效载荷是否存在以及它们的内容则取决于具体的报文类型。例如用于维持连接的 PINGREQ 报文就只有一个固定报头,用于传递应用消息的 PUBLISH 报文则完整地包含了这三个部分。

02packetformat.png

固定报头

固定报头由报文类型、标识位和报文剩余长度三个字段组成。

03fixedheader.png

报文类型位于固定报头第一个字节的高 4 位,它是一个无符号整数,很显然,它表示当前报文的类型,例如 1 表示这是一个 CONNECT 报文,2 表示 CONNACK 报文等等。详细的映射关系可以参阅 MQTT 5.0 规范 - MQTT 控制报文类型。事实上,除了报文类型和剩余长度这两个字段,MQTT 报文剩余部分的内容基本都取决于具体的报文类型,所以这个字段也决定了接收方应该如何解析报文的后续内容。

固定报头第一个字节中剩下的低 4 位包含了由控制报文类型决定的标识位。不过到 MQTT 5.0 为止,只有 PUBLISH 报文的这四个比特位被赋予了明确的含义:

  • Bit 3:DUP,表示当前 PUBLISH 报文是否是一个重传的报文。
  • Bit 2,1:QoS,表示当前 PUBLISH 报文使用的服务质量等级。
  • Bit 0:Retain,表示当前 PUBLISH 报文是否是一个保留消息。

其他所有的报文中,这 4 位都仍是保留的,即它们是一个固定的,不可随意变更的值。

最后的剩余长度指示了当前控制报文剩余部分的字节数,也就是可变报头和有效载荷这两个部分的长度。所以 MQTT 控制报文的总长度实际上等于固定报头的长度加上剩余长度。

04remaininglength.png

可变字节整数

但固定报头长度并不是固定的,为了尽可能地减少报文大小,MQTT 将剩余长度字段设计成了一个可变字节整数。

在 MQTT 中,存在很多长度不确定的字段,例如 PUBLISH 报文中的 Payload 部分就用来承载实际的应用消息内容,而应用消息的长度显然是不固定的。所以我们需要一个额外的字段来指示这些不定长内容的长度,以便接收端正确地解析。

一个 2 兆大小,也就是总共 2,097,152 个字节的应用消息,我们就需要一个 4 字节长度的整数才能够指示它的长度。但并不是所有的应用消息都有这么大,更多情况下是几 KB 甚至几个字节。用一个 4 字节长度的整数来指示一个总共 2 个字节长度的应用消息,显然是过于浪费了。

所以 MQTT 的可变字节整数就被设计出来了,它将每个字节中的低 7 位用于编码数据,最高的有效位用于指示是否还有更多的字节。这样,长度小于 128 字节时可变字节整数只需要一个字节就可以指示。可变字节整数的最大长度为 4 个字节,所以最多可以指示长度为 (2^28 - 1) 字节,也就是 256 MB 的数据。

05variablebyteinteger.png

可变报头

可变报头的内容取决于具体的报文类型。例如 CONNECT 报文的可变报头按顺序包含了协议名、协议级别、连接标识、Keep Alive 和属性这五个字段。PUBLISH 报文的可变报头则按顺序包含了主题名、报文标识符和属性这三个字段。

06variableheader.png

需要注意这里提到的顺序,可变报头中字段出现的顺序必须严格遵循协议规范,因为接收端只会按照协议规定的字段顺序进行解析。我们也不能随意地遗漏某个字段,除非是协议明确要求或允许的。例如,在 CONNECT 报文的可变报头中,如果协议名之后直接就是连接标识,那么就会导致报文解析失败。而在 PUBLISH 报文的可变报头中,报文标识符就只有在 QoS 不为 0 的时候才能存在。

属性

属性是 MQTT 5.0 引入的一个概念。属性字段基本上都是可变报头的最后一部分,由属性长度和紧随其后的一组属性组成,这里的属性长度指的是后面所有属性的总长度。

07propertiesinvariableheader.png

所有的属性都是可选的,因为它们通常都有一个默认值,如果没有任何属性,那么属性长度的值就为 0。

每个属性都由一个定义了属性用途和数据类型的标识符和具体的值组成。不同属性的数据类型可能不同,比如一个是双字节长度的整数,另一个则是 UTF-8 编码的字符串,所以我们需要按照标识符所声明的数据类型对属性进行解析。

08property.png

属性之间的顺序可以是任意的,这是因为我们可以根据标识符知道这是哪个属性,以及它的长度是多少。

属性通常都是为了某个专门的用途而设计的,比如在 CONNECT 报文中就有一个用于设置会话过期时间的的 Session Expiry Interval 属性,但显然我们在 PUBLISH 报文中就不需要这个属性。所以 MQTT 也严格定义了属性的使用范围,一个合法的 MQTT 控制报文中不应该包含不属于它的属性。

包含标识符、属性名、数据类型和使用范围的完整 MQTT 属性列表,请参阅 MQTT 5.0 Specification - Properties。

有效载荷

最后是有效载荷部分。我们可以将报文的可变报头看作是它的附加项,而有效载荷则用于实现这个报文的核心目的。

比如在 PUBLISH 报文中,Payload 用于承载具体的应用消息内容,这也是 PUBLISH 报文最核心的功能。而 PUBLISH 报文的可变报头中的 QoS、Retain 等字段,则是围绕着应用消息提供一些额外的能力。

SUBSCRIBE 报文也是如此,Payload 包含了想要订阅的主题以及对应的订阅选项,这也是 SUBSCRIBE 报文最主要的工作。

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
EMQ
|
7月前
|
Linux 网络性能优化
MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE
在 MQTT 中,SUBSCRIBE 报文用于发起订阅请求,SUBACK 报文用于返回订阅结果。而 UNSUBSCRIBE 和 UNSUBACK 报文则在取消订阅时使用。相比于取消订阅,订阅操作更加常用。不过在本文中,我们仍然会一并介绍订阅与取消订阅报文的结构与组成。
EMQ
399 6
MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE
EMQ
|
7月前
|
运维 Linux 网络性能优化
MQTT 5.0 报文解析 05:DISCONNECT
在 MQTT 中,客户端和服务端可以在断开网络连接前向对端发送一个 DISCONNECT 报文,来指示连接关闭的原因。客户端发送的 DISCONNECT 报文还可以影响服务端在连接断开后的行为,例如是否发送遗嘱消息,是否更新会话过期间隔。
EMQ
181 0
MQTT 5.0 报文解析 05:DISCONNECT
|
2月前
|
消息中间件 Java Kafka
RabbitMQ 入门
RabbitMQ 入门
|
5月前
|
消息中间件 新零售 弹性计算
云消息队列 RabbitMQ 版入门训练营,解锁对比开源优势与零基础实战
欢迎加入「云消息队列 RabbitMQ 版入门训练营」。
173 15
|
4月前
|
消息中间件 存储 Java
分享一下rocketmq入门小知识
分享一下rocketmq入门小知识
57 0
分享一下rocketmq入门小知识
EMQ
|
6月前
|
安全 开发工具 数据安全/隐私保护
MQTT 5.0 报文解析 06:AUTH
MQTT 5.0 引入了增强认证特性,它使 MQTT 除了简单密码认证和 Token 认证以外,还能够支持质询/响应风格的认证。为了实现这一点,它在原先 CONNECT 和 CONNACK 报文的基础上,又引入了 AUTH 报文来实现任意多次的认证数据交换,以支持各种不同类型的认证机制,例如 SCRAM、Kerberos 认证等等。
EMQ
311 7
MQTT 5.0 报文解析 06:AUTH
|
4月前
|
网络协议 物联网 测试技术
App Inventor 2 MQTT拓展入门(保姆级教程)
本文演示的是App和一个测试客户端进行消息交互的案例,实际应用中,我们的测试客户端可以看着是任意的、支持MQTT协议的硬件,通过订阅及发布消息,联网硬件与我们的App进行双向数据通信,以实现万物互联的智能控制效果。
226 2
EMQ
|
7月前
|
JSON Linux 网络性能优化
MQTT 5.0 报文解析 02:PUBLISH 与 PUBACK
本文将介绍在 MQTT 中用于传递应用消息的 PUBLISH 报文以及它的响应报文。不管是客户端向服务端发布消息,还是服务端向订阅端转发消息,都需要使用 PUBLISH 报文。决定消息流向的主题、消息的实际内容和 QoS 等级,都包含在 PUBLISH 报文中。
EMQ
430 10
MQTT 5.0 报文解析 02:PUBLISH 与 PUBACK
EMQ
|
7月前
|
Linux 网络性能优化 数据安全/隐私保护
MQTT 5.0 报文解析 01:CONNECT 与 CONNACK
如果我们想要使用 MQTT 进行通信,第一步必然是建立一个 MQTT 连接,而建立 MQTT 连接需要用到两个控制报文,它们分别是 CONNECT 报文与 CONNACK 报文。CONNECT 报文是客户端与服务端建立网络连接后,向服务端发送的第一个控制报文,用来发起连接请求。服务端将返回 CONNACK 报文告知客户端连接结果。
EMQ
925 11
MQTT 5.0 报文解析 01:CONNECT 与 CONNACK
|
6月前
|
消息中间件 存储 Kafka
01.RabbitMQ入门
01.RabbitMQ入门
60 0

相关产品

  • 云消息队列 MQ
  • 下一篇
    DataWorks