MQTT发布、订阅和取消订阅

在本文中,我们将深入了解MQTT发布、订阅和取消订阅相关的内容。如果你刚接触发布/订阅模型,建议阅读本专栏之前的文章。

什么是MQTT发布消息

在MQTT中,一个客户端连接到代理(broker)之后可以立即发布消息。这些消息依据主题被过滤,每个消息必须包含一个主题,这样代理(broker)可用来将消息转发订阅的客户端。每条消息的有效载荷包括要以字节格式传输的数据,发送客户端可以选择发送任何类型的数据,包括文本、数字、图像、二进制数据,甚至是xml和json.
image.png

MQTT是数据无关的,意味着可根据客户端指定的应用场景构建有效负载数据。有效负载数据是消息的主要内容和客户端订阅、接收和处理的。

在一个MQTT发布的信息中有几个属性来确定消息的行为,包括包标识符、主题名称、服务质量(QoS)、保留标志、有效负载、DUP标志,接下来我们分别介绍。

MQTT包标识符(packetId)

在MQTT中,包标识符(packetId)是一个基本的属性。它用来标记指定的消息,确保这些消息按照它们发送的顺序转发出去,特别是当QoS等级大于0时。packetId是客户端分配的,包含在PUBLISH, PUBREL, PUBREC和 PUBCOMP消息中。当代理(broker)收到一条PUBLISH消息,客户端已经指定一个packetId给这条信息,然后会向客户端发送一条包含该packetId的PUBACK消息。客户端使用PUBACK消息确认代理(broker)收到了消息。在这个过程中,packedId保持不变。

在MQTT协议中,关于消息发送和消息确认,被分为几个阶段:

  1. 发布(PUBLISH): 这是该过程的第一阶段,涉及到客户端发送一条消息到代理(broker)。这条信息包含一个主题和有效负载。
  2. 发布已接收(PUBREC): 收到PUBLISH消息后,代理(broker)会发送一条PUBREC消息来确认其已经收到消息。这是该过程的第二阶段。
  3. 发布释放(PUBREL): 一旦客户端收到PUBREC消息,它就会发送一条PUBREL消息,以解除代理(broker)将消息保存在内存中的责任。这是该过程的第三阶段。
  4. 发布完成(PUBCOMP): 代理(broker)最后发送一个PUBCOMP消息来确认它已经收到并处理了消息。这是该过程的第四阶段。

这四条消息是MQTT协议QoS的部分机制,确保消息的稳定发送。QoS等级决定了客户端和代理(broker)之间交换消息的数量。
值得注意的是,数据包标识符在客户端和代理(broker)之间流动时唯一标识消息。数据包标识符仅与大于0的QoS级别相关。不不仅适用于PUBLISH,也适用于SUBSCRIBE、UNSUBSCRIBE和CONNECT消息。
客户端库负责设置此内部MQTT标识。当QoS等级大于0时,客户端必须在发送下一条消息之前,必须等待一条来自代理(broker)的PUBACK或PUBREC消息。客户端同样需要跟踪它发送和接收的数据包标识符,确认消息没有丢失或重复。总之,数据包标识符对于MQTT的稳定机制非常重要,确保正确、高效的发送消息。

MQTT主题名称(topicName)

MQTT使用主题名称作为基本概念。它使用正斜杠作为分割符分层构造此名称,并创建一个简单的字符串。类似一个URL,但没有协议类型和域名。MQTT主题用来标记信息,为客户端提供一个订阅指定消息的途径。
例如,一个测量湿度的设备可能会发布它的值到主题“sensors/temperature/livingroom”。对这些值感兴趣的客户端可以订阅这个主题,接收更新后发布的值。
MQTT提供两类通配符,用在主题订阅上:

  • “+”(加号) 用来匹配单个层级。比如,评阅“sensors/+/livingroom”,会匹配“sensors/temperature/livingroom”和“sensors/humidity/livingroom”,但不会匹配“sensors/temperauture/kitchen”。
  • “#”(井号) 用来匹配多个层级。比如,订阅“sensors/#”,会匹配“sensors/temperature/livingroom”、“sensors/humidity/kitchen”和"sensors/power/meter1".

订阅大量主题会对代理(broker)的性能有重大影响。这是因为发布到客户端订阅的主题的每条消息都必须传递到该客户端。如果很多客户端订阅了很多主题,这会迅速变成代理(broker)的沉重负担。
使用通配符,通过一个订阅来订阅多个主题同样影响性能。当一个客户端订阅一个含有通配符的主题,代理必须评估发送来的每条消息来匹配主题,以确定是否将消息转发给该客户端。如果匹配的主题很多,这就会限制代理(broker)的资源。
为了避免性能问题,高效的使用主题订阅非常重要。一个重要原则就是尽可能使用确定的主题过滤,而不是依赖通配符。另一个原则就是使用分享订阅,,就是允许多个客户端分享一个主题的订阅。这就会减少订阅量和代理(broker)必须处理的消息。最后,监控代理(broker)的性能,根据需要调整配置来确保最优性能也很重要。

MQTT中的QoS

在之前文章中(http://t.csdnimg.cn/zJblm)简单提过QoS。QoS由一个介于0到2之间的数字表示。每个层级都为消息传递提供不同级别的可靠性和保证。

  • QoS 0(最多一次): 这个等级并不保证消息被发送出去。消息被发送一次,如果丢失或接收端没有收到,消息不会重新发送。
  • QoS 1(至少一次): 这个等级消息至少被发送一次,但是,可能会因为网络原因或发送失败,发送多次。
  • QoS 2(确切一次): 这个等级为消息发送提供最高等级的保证。确保消息发送一次,但是这个等级会要求发送方和接收方多次通信,会增加网络延迟和网络流量。

根据具体的应用场景,选择合适的QoS等级。比如,QoS 0可能适用于是重要的数据,QoS 2可能对重要的、需要高稳定等级的数据很有必要。
需要注意的是,QoS等级会影响代理(broker)和网络的性能,所以建议根据具体的应用场景选择合适的等级。关于这部分,后续会深入讨论。

MQTT中的保留标志(retainFlag)

保留标志是一项重要功能,用于确定代理(broker)是否将消息保存为指定主题的最后一个已知良好值。当保留标志被设置成true时,代理(broker)将会保留匹配指定主题的最近的消息,无论是否有订阅的客户端。
当有一个新的客户端订阅有保留消息的主题时,代理(broker)就会发送最后保留的消息给该客户端。这就允许客户端接收最近的相关信息,即使之前没有订阅该主题。
同样需要注意的是,类似前面提到的其他元素,保留标记的使用也会影响代理(broker)的性能,特别是当有很多保留消息时。另外,如果一个保留消息经常被更新,就会增加网络流量,可能影响网络的性能。
更多关于保留标志的内容及如何使用保留标志,会在后续文章中介绍。

MQTT中的负载(payload)

负载是消息中的实际内容,可以包含任意类型的数据。MQTT是数据无关的,意味着可以处理不同的数据类型,包括图像、任意编码的文本、加密数据和二进制数据。但是,要注意的是,负载的大小会影响网络的性能、客户端和代理的内存使用。因此,建议使负载尽可能的小,特别是当高频率的推送数据时。

MQTT中的DUP标志(dupFlag)

DUP标志表明这个消息是一个复本,因为原接收端(客户端或代理)没有确认最初的消息,所以被重新发送。只和QoS等级大于0的消息相关。当一个客户端或代理(broker)收到一个有DUP标记的消息,如果和已经收到的消息的ID相同,则应该忽略该消息。如果之前没有收到,则应该正常处理该消息。
MQTT协议(MQTT客户端库或代理)自动处理重发和复制机制,但需要注意的是这会影响网络性能,增加网络流量。更多内容,会在后续文章中介绍。

MQTT代理(broker)如何处理来自客户端的消息

当一个客户端发布消息到MQTT代理(broker),代理(broker)会进行几项工作来确保根据客户端指定的QoS等级将消息发送出去。具体如下:

  1. 消息接收: 代理(broker)读取客户端发送的消息,验证消息的语法和格式。
  2. 确认: 代理(broker)发送一个确认消息到客户端,来确认收到了消息。确认的等级依赖于QoS等级。
  3. 处理: 代理确认哪些客户端订阅了该消息的主题,将消息的复本发送给它们当中的每一个。依据保留标志,代理可能也会保留该主题的最后的好的消息。
  4. 反馈: 发布消息的客户端收到来自代理的确认消息,指示该消息已成功发送。但是,客户端不会收到有多少订阅者收到消息的反馈或是否有客户端对该消息感兴趣。

最初发送消息的客户端只关心发送到代理的PUBLISH消息。代理(broker)一旦收到PUBLISH消息,其责任就是将消息发送给所有的订阅者。发送的客户端不会收到任务关于是否有人对发送的消息感兴趣或有多少客户端从代理(broker)收到了该消息的反馈。

如何订阅MQTT主题

如果没有人接收,发布消息将没有任何意义,这就是订阅的意义。一旦一个客户端发布一条消息到MQTT代理(broker),该消息必须被发送给对其感兴趣的客户端。对该主题有兴趣的、希望接收该信息的客户端发送一个SUBSCRIBE消息到代理(broker)。SUBSCRIBE消息很简单,包含一个唯一的标识符ID(packetId)和一个订阅列表。

标识符ID(packetId): 标识符ID是唯一的,标记一条在客户端和代理(broker)之间流动的消息,客户端负载设置此内部MQTT标识符。
订阅列表: 一条SUBSCRIBE消息能够包含多条订阅。每个订阅包括一个主题和一个QoS等级。主题可以包含通配符,使订阅主题模式而不是一个确定的主题成为可能。如果有重叠的订阅,代理(broker)会发送该主题高QoS等级的消息给客户端。
总之,MQTT允许客户端订阅指定的主题,接收发布到这些主题的消息,根据它们的应用场景处理负载数据。SUBSCRIBE消息中的标识符ID(packetId)和QoS等级确保消息以合适的4质量等级被可靠的发送。
一个客户端一旦发送一条包含期望主题和QoS等级的SUBSCRIBE消息到MQTT代理(broker),代理(broker)用一条SUBACK消息回复,确认订阅,指定代理会发送的最高QoS等级。

MQTT的Suback

客户端一旦发送一条包含主题和QoS等级的消息到代理(broker),代理(broker)通过发送一条SUBACK消息到客户端来确认订阅请求。SUBACK消息确认收到了SUBSCRIBE消息,表明代理(broker)已经接受或拒绝每个订阅。

包标识符(packedId): SUBACK消息中包含着和SUBSCRIBE消息中同样的包标识符,确保客户端和开始的请求匹配确认。
返回码(returnCode): SUBACK消息中还包括对应SUBSCRIBE消息中每一对主题/QoS的返回码。返回码的值是二进制,指示代理(broker)是已批准还是拒绝每个主题的订阅请求。
QoS等级的返回码如下:

  • QoS 0: 意味着订阅请求被授予QoS 0 等级。消息一旦可用,代理(broker)马上发送消息到客户端,不保证质量。
  • QoS 1: 意味着订阅请求被授予QoS 1 等级。代理(broker)至少发送一次消息,意味着代理(broker)至少发送一次消息到客户端。客户端收到消息后返回一条PUBACK消息进行确认。
  • QoS 2: 意味着订阅请求被授予QoS 2 等级。代理(broker)确切的发送一次消息,意味着代理(broker)保证消息被发送一次且只有一次到客户端。客户端收到消息后返回一条PUBREC消息到代理(broker)进行确认。代理收到PUBREC消息后发送一条PUBREL消息到客户端,然后客户端收到PUBREL消息后发送一条PUBCOMP消息到代理(broker)。

如果代理拒绝 SUBSCRIBE 消息中的任何订阅,那么 SUBACK 消息将包含该特定主题的失败返回码。失败的原因可能是客户端没有足够的权限来订阅主题、主题格式不正确或其他原因。
失败返回码由0x80表示,指示代理不接受订阅。如果客户端没有足够的权限来订阅主F题、主题格式不正确或订阅请求存在其他问题,则可能会发生这种情况。当客户端收到一个失败返回码,它需要使用不同的主题或QoS等级来重新订阅或采取合适的措施解决订阅请求的问题。

Return CodeReturn Code Response
0Success - Maximum QoS 0
1Success - Maximum QoS 1
2Success - Maximum QoS 2
128Failure

SUBACK是来自代理(broker)、发送到客户端的确认请求被接受或拒绝的消息。数据包标识符(packedId)使客户端能够将确认与原始请求相匹配,而返回代码指示代理授予订阅的 QoS 级别。
当客户端评阅了它感兴趣的主题,并且收到发布到这些主题的消息,它最终可能需要取消订阅。接下来让我们看下SUBSCRIBE消息相对的部分:UNSUBSCRIBE消息和确认取消订阅的UNSUBACK消息。

如何使用MQTT中的退订功能撤销订阅?

在 MQTT 中,客户端可以通过向代理发送 UNSUBSCRIBE 消息来取消订阅它们已订阅的主题。与 SUBSCRIBE 类似,此消息包括用于唯一标识它的数据包标识符和要取消订阅的主题列表。

包标识符(packetId): 和SUBSCRIBE消息中的类似,UNSUBSCRIBE 消息中的数据包标识符用作客户端和代理之间消息流的内部 MQTT 标识符。它确保客户端和代理可以跟踪消息及其相应的确认消息。
主题列表: 取消订阅消息中的主题列表可以包含客户端要取消订阅的一个或多个主题。无需指定 QoS 级别,因为无论最初订阅的 QoS 级别如何,代理都会取消订阅主题。

MQTT Unsuback

当收到UNSUBSCRIBE消息后,代理(broker)发送一条UNSUBACK消息来确认客户端订阅的删除。这个消息包括UNSUBSCRIBE消息的包标识符(packetId),作为代理(broker)已经成功从客户端的订阅列表中移除主题的确认。

数据包标识符: UNSUBACK消息中的数据包标识符与对应的UNSUBSCRIBE消息中的数据包标识符相同。这可确保客户端可以识别确认消息并将其与原始取消订阅消息相关联。
返回码: UNSUBACK 消息包含已取消订阅的每个主题/QoS 对的返回代码列表。返回代码 0 表示删除成功,而返回代码 17 表示由于主题无效或格式不正确而删除不成功。还可以为不同的错误方案指定其他返回代码。
从代理(broker)收到 UNSUBACK 后,客户端可以假定 UNSUBSCRIBE 消息中的订阅已被删除。
通过这些详细信息,可以全面了解客户端如何取消订阅主题,以及代理如何分别通过 UNSUBSCRIBE 和 UNSUBACK 消息确认删除这些订阅。

结论

MQTT 提供了一种灵活且与数据无关的方法,用于在客户端和代理(broker)之间发布消息。通过使用主题过滤消息,客户端可以快速轻松地订阅它们感兴趣的内容。可以自定义每条消息的有效负载(payload)以满足每个客户端的特定需求,MQTT 对各种数据类型的支持使其成为许多用例的多功能解决方案。此外,了解 PUBLISH 消息的属性(如 QoS 级别和保留标志)可以帮助客户端和代理确保高效可靠地传递消息。
后续的文章中,会详细讨论主题(topic)相关的内容,如何使用通配符等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/213006.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NetSuite预算管理实践

NetSuite预算相关的原生功能有两个: 一个是Expense Commitments And Budget Validation这个SuiteApp,我们在一年前写过一篇文章介绍过。它强调预算的过程控制,但由于功能很有限,没有实际用处。 NetSuite Budget功能包_netsuite …

Vue3 pinia的基本使用

pinia的使用跟vuex很像,去除了很多没用的api,写法有两种,一种老式的选项式api还有一种组合式api,用哪种根据自己喜好来,以下示例为组合式api 更多教程参考官网:pinia官网https://pinia.vuejs.org/zh/ 安装…

机器学习基本概念2

资料来源: https://www.youtube.com/watch?vYe018rCVvOo&listPLJV_el3uVTsMhtt7_Y6sgTHGHp1Vb2P2J&index1 https://www.youtube.com/watch?vbHcJCp2Fyxs&listPLJV_el3uVTsMhtt7_Y6sgTHGHp1Vb2P2J&index2 分三步 1、 定义function b和w是需要透…

linux之autoconf(1)基础介绍

Linux之autoconf(1)基础介绍 Author:Onceday Date:2023年2023年12月10日 漫漫长路,才刚刚开始… 本文主要内容翻译自Autoconf官方文档,仅供学习交流之用。 全系列文章请查看专栏: buildroot编译框架_Once_day的博客-CSDN博客。…

FL Studio21最新FL水果编曲软件中文版在哪下载?

FL Studio21水果编曲软件是一款专业的音乐制作软件,被广泛地应用于电子音乐、hip-hop、流行乐等多种音乐类型的制作。该软件提供了丰富的音频编曲工具和音乐效果器,让用户可以轻松地创作出高品质的音乐作品。同时,这也是一款非常易于上手的软…

[ 云计算 | Azure 实践 ] 在 Azure 门户中创建 VM 虚拟机并进行验证

文章目录 一、前言二、在 Azure Portal 中创建 VM三、验证已创建的虚拟机资源3.1 方法一:在虚拟机服务中查看验证3.1 方法二:在资源组服务中查看验证 四、文末总结 一、前言 本文会开始创建新系列的专栏,专门更新 Azure 云实践相关的文章。 …

YOLOv8改进 | 2023检测头篇 | 利用AFPN改进检测头适配YOLOv8版(全网独家创新)

一、本文介绍 本文给大家带来的改进机制是利用今年新推出的AFPN(渐近特征金字塔网络)来优化检测头,AFPN的核心思想是通过引入一种渐近的特征融合策略,将底层、高层和顶层的特征逐渐整合到目标检测过程中。这种渐近融合方式有助于…

软件无线电SDR-频谱采集python实现

sdr做的频谱采集,保存的500张频谱图,能看出来是什么东西吗?

VC++使用GetProcessTimes获取进程创建时间、销毁时间、用户态时间、内核态时间

一、GetProcessTimes函数简介(微软MSDN) 微软提供了一个非常有用的API函数GetProcessTimes用来获取进程创建时间、销毁时间、用户态时间、内核态时间,msdn连接为:GetProcessTimes 函数 (processthreadsapi.h) 其函数原型为&#…

基于NIQE算法的图像无参考质量评价算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 空域NSS特征提取 4.2 图像块选取 4.3 MVG模型 4.4 NIQE指标 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 clc; clear; close all; …

轻量封装WebGPU渲染系统示例<46>- 材质组装管线(MaterialPipeline)灯光、阴影、雾以及多Pass(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/MaterialPipelineMultiPasses.ts 当前示例运行效果: 此示例基于此渲染系统实现,当前示例TypeScript源码如下: export class MaterialPipelin…

java实现网络聊天

网络聊天实现步骤(从功能谈论方法): 客户端: 1.登录面板:注册提醒用户注册格式,登录账号密码不为空,点击登录的时候需要连接服务器端,启动聊天面板。(监听用户点击登录…

Windows下nginx的启动,重启,关闭等功能bat脚本

echo off rem 提供Windows下nginx的启动,重启,关闭功能echo begincls ::ngxin 所在的盘符 set NGINX_PATHG:::nginx 所在目录 set NGINX_DIRG:\projects\nginx-1.24.0\ color 0a TITLE Nginx 管理程序增强版CLSecho. echo. ** Nginx 管理程序 *** echo.…

JAVA使用HTTP代码示例

你好,Java开发者们!今天,我要给你们带来一场硬核的盛宴,那就是在Java中使用HTTP协议进行网络通信的代码示例。准备好接受挑战了吗?Lets go! 首先,我们需要导入一些必要的库,它们将成…

C++枚举类

枚举 C11有作用域枚举和无作用域枚举 无作用域枚举 特点 全局作用域:无作用域枚举的成员(枚举值)在包含它们的作用域内是直接可见的,不需要使用枚举类型名称作为前缀。 隐式类型转换:无作用域枚举的成员可以隐式地转换…

鸿蒙开发组件之ForEach列表

一、ForEach函数 ForEach函数是一个迭代函数,需要传递两个必须参数和一个可选参数。主要通过迭代来获取参数arr中的数据不断的生成单个Item来生成鸿蒙中的列表样式 二、先创建单个的Item的UI 通过嵌套Row与Column来实现单个Item的UI。例如图中没有折扣的可以看成一…

用23种设计模式打造一个cocos creator的游戏框架----(八)适配器模式

1、模式标准 模式名称:适配器模式 模式分类:结构型 模式意图:适配器模式的意图是将一个类的接口转换成客户端期望的另一个接口。适配器模式使原本接口不兼容的类可以一起工作。 结构图: 适用于: 系统需要使用现有的…

309. 买卖股票的最佳时机含冷冻期(leetcode) 动态规划思想

文章目录 前言一、题目分析二、算法原理1.状态表示2.状态转移方程3.初始化边界条件4.填表顺序5.返回值是什么 三、代码实现总结 前言 在本文章中,我们将要详细介绍一下Leetcode中买卖股票的最佳时机含冷冻期相关的内容,本题采用动态规划的思想解决 一、…

PyQt6 QDateEdit日期控件

​锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计39条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话…

空中消防员:无人机森林防火应用全面升级

森林是生态系统的重要组成部分,也是人类得以生存的关键。我国森林面积广大,存在火灾频发的困境。提升森林火灾防控能力是维护生态平衡、保护资源和保障人民生命安全的必要步骤。随着无人机技术的发展,其在无人机森林防火中的应用为传统巡查工…