MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE

2024-05-07 23:52

本文主要是介绍MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

欢迎阅读 MQTT 5.0 报文系列 的第三篇文章。在上一篇中,我们介绍了 MQTT 5.0 的 PUBLISH 及其响应报文。现在,我们将介绍用于订阅和取消订阅的控制报文。

在 MQTT 中,SUBSCRIBE 报文用于发起订阅请求,SUBACK 报文用于返回订阅结果。而 UNSUBSCRIBE 和 UNSUBACK 报文则在取消订阅时使用。相比于取消订阅,订阅操作更加常用。不过在本文中,我们仍然会一并介绍订阅与取消订阅报文的结构与组成。

报文示例

首先我们借助 Wireshark 来捕获一次真实的 MQTT 订阅请求与响应,这里我们使用 MQTTX CLI 向 公共 MQTT 服务器 发起订阅请求。以下命令将创建一个主题为 demo,且最大 QoS 设置为 2 的订阅:

mqttx sub --hostname broker.emqx.io --mqtt-version 5 --topic demo --qos 2

以下是 Wireshark 捕获到的 SUBSCRIBE 和 SUBACK 报文数据:

# SUBSCRIBE
82 0a 05 be 00 00 04 64 65 6d 6f 02# SUBACK
90 04 05 be 00 02

Linux 环境可以先使用 tcpdump 命令抓取报文,然后导入至 Wireshark 分析。

这些由十六进制字节组成的原始且晦涩的报文数据,它们分别对应着以下报文内容:

01subscribepacket.png

02subackpacket.png

也许你开始好奇它们是如何完成从简单的 MQTTX CLI 命令到复杂的报文数据的转换,或者好奇当你捕获到一个 MQTT 报文,你应该如何从中提取你想要的信息。

那么在接下来的 SUBSCRIBE、SUBACK、UNSUBSCRIBE 以及 UNSUBACK 的报文结构的介绍中,你的疑问将得到解答。

SUBSCRIBE 报文结构

固定报头

在 SUBSCRIBE 报文中,固定报头中首字节的高 4 位值必须为 8(0b1000),而低 4 位保留位必须被设置为 2(0b0010)。第一个字节之后,仍然是剩余长度(Remaining Length)字段,它是一个可变字节整数。

SUBSCRIBE 固定报头

可变报头

SUBSCRIBE 报文的可变报头按顺序包含以下字段:

SUBSCRIBE 可变报头

  • 报文标识符(Packet Identifier):一个两个字节长度的无符号整数,用来唯一地标识订阅请求。PUBLISH、SUBSCRIBE、UNSUBSCRIBE 报文使用一组报文标识符,这表示它们不能同时使用同一个报文标识符。
  • 属性(Properties):下表列出了 SUBSCRIBE 报文的所有可用属性。
IdentifierProperty NameType
0x0BSubscription Identifier变长字节整数
0x26User PropertyUTF-8 字符串对

有效载荷

SUBSCRIBE 报文的有效载荷包含一个或多个主题过滤器/订阅选项对。主题过滤器是一个 UTF-8 编码的字符串,用于向服务端指明客户端希望订阅的主题,订阅选项则仅占用一个字节,目前由以下四个选项组成:

  • Reserved (Bit 7, 6):保留位,目前必须设置为 0。
  • Retain Handling (Bit 5, 4):用于指示当订阅建立时,服务端是否需要向此订阅发送保留消息。
  • Retain As Published (Bit 3):用于指示服务端在向此订阅转发应用消息时是否需要保持消息中的 Retain 标志。
  • No Local (Bit 2):用于指示服务端是否可以将应用消息转发给该消息的发布者。No Local 和 Retain As Published 通常用于桥接场景。
  • Maximum QoS (Bit 1, 0):这个选项决定了服务端向此订阅转发消息时可以使用的最大 QoS 等级。如果消息的原始 QoS 超过了这个限制,那么服务端就会对 QoS 进行降级以保证消息的传递。

SUBSCRIBE 报文的有效载荷

SUBACK 报文结构

固定报头

SUBACK 报文的首字节高 4 位的值为 9(0b1001),低 4 位都必须全部被设置为 0。

SUBACK 固定报头

可变报头

SUBACK 的可变报头按顺序包含以下字段:

SUBACK 可变报头

  • 报文标识符(Packet Identifier):SUBACK 报文中的报文标识符必须与对应的 SUBSCRIBE 报文一致,以便另一方正确地将响应与请求匹配。
  • 属性(Properties):下表列出了 SUBACK 报文的所有可用属性。
IdentifierProperty NameType
0x1FReason StringUTF-8 编码的字符串
0x26User PropertyUTF-8 字符串对

有效载荷

SUBACK 报文的有效载荷包含了一个 Reason Code 列表,Reason Code 指示了订阅是否成功或者失败的原因。一个 Reason Code 对应 SUBSCRIBE 报文的一个主题过滤器,所以 SUBACK 报文中 Reason Code 的顺序必须与 SUBSCRIBE 报文中主题过滤器的顺序一致。

SUBACK 有效载荷

下表列出了 SUBACK 报文可用的所有 Reason Code:

ValueReason Code NameDescription
0x00Granted QoS 0订阅被接受且最大 QoS 等级为 0。服务端授予的 QoS 等级可能低于客户端请求的 QoS 等级,这主要取决于服务端是否支持所有 QoS 或者是相应的权限设置。
0x01Granted QoS 1订阅被接受且最大 QoS 等级为 1。
0x02Granted QoS 2订阅被接受且最大 QoS 等级为 2。
0x80Unspecified error表示未指明的错误。当一方不希望向另一方透露错误的具体原因,或者协议规范中没有能够匹配当前情况的 Reason Code 时,那么它会在报文中使用这个 Reason Code。
0x83Implementation specific errorSUBSCRIBE 报文有效,但是不被当前服务端的实现所接受。
0x87Not authorized客户端无权进行此订阅。
0x8FTopic Filter invalid主题过滤器的格式正确,但是不被服务端接受。比如主题过滤器的层级超过了服务端允许的最大数量限制。
0x91Packet Identifier in use收到报文中的 Packet ID 正在被使用。
0x97Quota exceeded表示超出了配额限制。服务端可能会对订阅端的订阅配额进行限制,比如一个客户端最多建立 10 个订阅。
0x9EShared Subscriptions not supported服务端不支持共享订阅。
0xA1Subscription Identifiers not supported服务端不支持订阅标识符。
0xA2Wildcard Subscriptions not supported服务端不支持通配符订阅。

UNSUBSCRIBE 报文结构

固定报头

与 SUBSCRIBE 报文相同,唯一的区别是报文类型字段的值从 8(0b1000) 变成了 10(0b1010)。

UNSUBSCRIBE 固定报头

可变报头

与 SUBSCRIBE 报文相同。

有效载荷

UNSUBSCRIBE 报文的有效载荷包含一个或多个客户端希望取消订阅的主题过滤器,这些主题过滤器同样是 UTF-8 编码的字符串,并且多个主题过滤器紧密相连。

UNSUBSCRIBE 有效载荷

UNSUBACK 报文结构

固定报头

UNSUBACK 报文的首字节高 4 位的值为 11(0b1011),低 4 位都必须全部被设置为 0。

UNSUBACK 固定报头

可变报头

UNSUBACK 的可变报头按顺序包含报文标识符和属性字段,可用的属性与 SUBACK 报文相同。

有效载荷

UNSUBACK 报文的有效载荷同样包含了一个 Reason Code 列表,Reason Code 指示了取消订阅是否成功或者失败的原因。这些 Reason Code 按顺序对应 UNSUBSCRIBE 报文的主题过滤器。

UNSUBACK 有效载荷

下表列出了 UNSUBACK 报文可用的所有 Reason Code:

ValueReason Code NameDescription
0x00Success订阅已被删除
0x11No subscription existed服务端中不存在该订阅。
0x80Unspecified error取消订阅无法完成,服务器要么不希望透露原因,要么没有其他原因代码适用。
0x83Implementation specific errorUNSUBSCRIBE 报文有效,但是不被当前服务端的实现所接受。
0x87Not authorized客户端无权取消此订阅。
0x8FTopic Filter invalid主题过滤器的格式正确,但是不被服务端接受。比如主题过滤器的层级超过了服务端允许的最大数量限制。
0x91Packet Identifier in use收到报文中的 Packet ID 正在被使用。

总结

SUBSCRIBE 和 SUBACK 报文用于订阅,UNSUBSCRIBE 和 UNSUBACK 用于取消订阅,想要订阅或者取消订阅的主题过滤器列表,都在对应报文的有效载荷中,SUBSCRIBE 报文中的每个主题主题过滤器,都与一组订阅选项相关联。

指示请求结果的 Reason Code 位于 SUBACK 和 UNSUBACK 报文的有效载荷部分,并且它是一个列表,一一对应请求报文中的主题过滤器。

在下一篇文章中,我们将继续研究 MQTT 的心跳报文。

这篇关于MQTT 5.0 报文解析 03:SUBSCRIBE 与 UNSUBSCRIBE的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968753

相关文章

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)

《使用Java解析JSON数据并提取特定字段的实现步骤(以提取mailNo为例)》在现代软件开发中,处理JSON数据是一项非常常见的任务,无论是从API接口获取数据,还是将数据存储为JSON格式,解析... 目录1. 背景介绍1.1 jsON简介1.2 实际案例2. 准备工作2.1 环境搭建2.1.1 添加

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

你的华为手机升级了吗? 鸿蒙NEXT多连推5.0.123版本变化颇多

《你的华为手机升级了吗?鸿蒙NEXT多连推5.0.123版本变化颇多》现在的手机系统更新可不仅仅是修修补补那么简单了,华为手机的鸿蒙系统最近可是动作频频,给用户们带来了不少惊喜... 为了让用户的使用体验变得很好,华为手机不仅发布了一系列给力的新机,还在操作系统方面进行了疯狂的发力。尤其是近期,不仅鸿蒙O

Java解析JSON的六种方案

《Java解析JSON的六种方案》这篇文章介绍了6种JSON解析方案,包括Jackson、Gson、FastJSON、JsonPath、、手动解析,分别阐述了它们的功能特点、代码示例、高级功能、优缺点... 目录前言1. 使用 Jackson:业界标配功能特点代码示例高级功能优缺点2. 使用 Gson:轻量

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库