MQTT 订阅选项的使用

在 MQTT 发布/订阅模式介绍这篇博客中,我们已经了解到,我们需要先向服务端发起订阅,才能从服务端接收对应的消息。如果说订阅时指定的主题过滤器决定了服务端将向我们转发哪些主题下的消息,那么订阅选项则是允许我们进一步定制服务端的转发行为。

在本文中,我们将重点介绍在 MQTT 中哪些订阅选项可供我们使用,以及它们的使用方法。

订阅选项

在 MQTT 中,一个订阅由一个主题过滤器和对应的订阅选项组成。所以理论上,我们可以为每个订阅都设置不同的订阅选项。

MQTT 5.0 提供了 4 个订阅选项,分别是 QoS、No Local、Retain As Published、Retain Handling,而 MQTT 3.1.1 则仅提供了 QoS 这一个订阅选项。不过这些 MQTT 5.0 新增的订阅选项的默认行为,仍与 MQTT 3.1.1 保持一致,如果你正准备从 MQTT 3.1.1 升级到 MQTT 5.0,这会非常地友好。

现在,让我们一起看看这些订阅选项的作用吧。

QoS

QoS 是最常用的一个订阅选项,它表示服务端在向订阅端发送消息时可以使用的最大 QoS 等级。

客户端可能会在订阅时指定一个小于 2 的 QoS,因为它的实现不支持 QoS 1 或者 QoS 2。而如果服务端支持的最大 QoS 小于客户端订阅时请求的最大 QoS,那么显然服务端将无法满足客户端的要求,这时服务端就会通过订阅的响应报文(SUBACK)告知订阅端最终授予的最大 QoS 等级,订阅端可以自行评估是否接受并继续通信。

image.png

一个简单的计算公式:

服务端最终授予的最大 QoS = min ( 服务端支持的最大 QoS, 客户端请求的最大 QoS )

但是,我们在订阅时请求的最大 QoS,并不能限制发布端发布消息时使用的 QoS。当我们订阅时请求的最大 QoS,小于消息发布时的 QoS 时,为了尽可能地投递消息,服务端不会忽略这些消息,而是会在转发时对这些消息的 QoS 进行降级处理。

image.png

同样,我们也有一个简单的计算公式:

消息被转发时的 QoS = min ( 消息原始的 QoS, 服务端最终授予的最大 QoS )

No Local

No Local 只有 0 和 1 两个可取值,为 1 表示服务端不能将消息转发给发布这个消息的客户端,为 0 则相反。

这个选项通常被用在桥接场景中。桥接本质上是两个 MQTT Server 建立了一个 MQTT 连接,然后相互订阅一些主题,Server 将客户端的消息转发给另一个 Server,而另一个 Server 则可以将消息继续转发给它的客户端。

image.png

那么最简单的一个例子,我们假设两个 MQTT Server 分别是 Server A 和 Server B,它们分别向对方订阅了 # 主题。现在,Server A 将一些来自客户端的消息转发给了 Server B,而当 Server B 查找匹配的订阅时,Server A 也会位于其中。如果 Server B 将消息转发给了 Server A,那么同样 Server A 在收到消息后又会把它们再次转发给 Server B,这样就陷入了无休止的转发风暴。

而如果 Server A 和 Server B 在订阅 # 主题的同时,将 No Local 选项设置为 1,就可以完美地避免这个问题。

Retain As Published

Retain As Published 同样只有 0 和 1 两个可取值,为 1 表示服务端在向此订阅转发应用消息时需要保持消息中的 Retain 标识不变,为 0 则表示必须清除。

Retain As Published 与 No Local 一样,同样也是主要适用于桥接场景。我们知道当服务端收到一条保留消息时,除了将它存储起来,还会将它像普通消息一样转发给当前已经存在的订阅者,并且在转发时会清除消息的 Retain 标识。

这在桥接场景下带来了一些问题。我们继续沿用前面的设定,当 Server A 将保留消息转发给 Server B 时,由于消息中的 Retain 标识已经被清除,Server B 将不会知道这原本是一条保留消息,自然不会再存储它。这就导致了保留消息无法跨桥接使用。

那么在 MQTT 5.0 中,我们可以让桥接的服务端在订阅时将 Retain As Published 选项设置为 1,来解决这个问题。

image.png

Retain Handling

Retain Handling 这个订阅选项被用来向服务端指示当订阅建立时,是否需要发送保留消息。

我们知道默认情况下,只要订阅建立,那么服务端中与订阅匹配的保留消息就会下发。

但某些时候,客户端可能并不想接收保留消息,比如客户端在连接时复用了会话,但是客户端无法确认上一次连接中是否成功创建了订阅,所以它可能会再次发起订阅。如果订阅已经存在,那么可能保留消息已经被消费过了,也可能服务端已经在会话中缓存了一些离线期间到达的消息,这时客户端可能并不希望服务端发布保留消息。

另外,客户端也可能在任何时刻都不想收到保留消息,即使是第一次订阅。比如我们将开关状态作为保留消息发送,但对某个订阅端来说,开关事件将触发一些操作,那么在这种情况下不发送保留消息是很有用的。

这三种不同的行为,我们可以通过 Retain Handling 来选择。

  • 将 Retain Handling 设置为 0,表示只要订阅建立,就发送保留消息;

  • 将 Retain Handling 设置为 1,表示只有建立全新的订阅而不是重复订阅时,才发送保留消息;

  • 将 Retain Handling 设置为 2,表示订阅建立时不要发送保留消息。

演示

订阅选项 QoS 的演示

  1. 在 Web 浏览器上访问 MQTTX Web。

  2. 创建一个使用 WebSocket 的 MQTT 连接,并且连接免费的 公共 MQTT 服务器:

    MQTTX

  3. 连接成功后,我们订阅主题 mqttx_4299c767/demo,并指定 QoS 为 0。由于公共服务器可能同时被很多人使用,为了避免主题与别人重复,我们可以将 Client ID 作为主题前缀:

    Subscribe to the topic "mqttx_4299c767/demo"

  4. 订阅成功后,我们向主题 mqttx_4299c767/demo 发布一条 QoS 1 消息,这时我们将看到,我们发出的是 QoS 1 消息,但收到的却是 QoS 0 消息,这说明发生了 QoS 降级:

    Publish a QoS 1 message

订阅选项 No Local 的演示

  1. 在 Web 浏览器上访问 MQTTX Web。

  2. 创建一个使用 WebSocket 的 MQTT 连接,并且连接免费的公共 MQTT 服务器。

  3. 连接成功后,我们订阅主题 mqttx_4299c767/demo,并且将 No Local 设置为 true:

    Subscribe to the topic "mqttx_4299c767/demo"

  4. 订阅成功后,与前面 QoS 的演示一样,我们还是由订阅端自己来发布消息,但这一次我们会发现订阅端将无法收到消息:

    Publish MQTT Message

订阅选项 Retain As Published 的演示

  1. 在 Web 浏览器上访问 MQTTX Web。

  2. 创建一个使用 WebSocket 的 MQTT 连接,并且连接免费的公共 MQTT 服务器。

  3. 连接成功后,我们先订阅主题 mqttx_4299c767/rap0,并且将 Retain As Published 设置为 false,然后订阅主题 mqttx_4299c767/rap1,并且将 Retain As Published 设置 true:

    Subscribe to the topic "mqttx_4299c767/rap0"

    Subscribe to the topic "mqttx_4299c767/rap1"

  4. 订阅成功后,我们分别向主题 mqttx_4299c767/rap0mqttx_4299c767/rap1 发布一条保留消息,我们将看到前者收到的消息中 Retain 标识被清除,而后者收到的消息中 Retain 标识被保留:

    Receive messages

订阅选项 Retain Handling 的演示

  1. 在 Web 浏览器上访问 MQTTX Web。

  2. 创建一个使用 WebSocket 的 MQTT 连接,并且连接免费的公共 MQTT 服务器。

  3. 连接成功后,我们先向主题 mqttx_4299c767/rh 发布一条保留消息。然后订阅主题 mqttx_4299c767/rh,并且将 Retain Handling 设置为 0:

    Publish a retained message to the topic "mqttx_4299c767/rh"

  4. 订阅成功后,我们将收到服务端发送的保留消息:

    Receive the retained message

  5. 取消当前订阅,重新订阅主题 mqttx_4299c767/rh,并且将 Retain Handling 设置为 2。不过这一次订阅成功后,我们将不会收到服务端发送的保留消息:

    Retain Handling set to 2

在 MQTTX 中,我们没有办法演示 Retain Handling 设置为 1 时的效果。不过你可以在 这里 获取订阅选项的 Python 示例代码。

版权声明: 本文为 EMQ 原创,转载请注明出处。
原文链接:https://www.emqx.com/zh/blog/an-introduction-to-subscription-options-in-mqtt

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从零搭建vue+electron桌面应用

从零搭建vueelectron桌面应用 一、准备工作1.全局下载electron2.全局下载vue脚手架3.创建vue项目(这里用的是vue2版本)4.安装打包插件5.安装electron-builder,安装后可以直接生成主进程的配置文件6.在vue.config.js中添加以下配置 二、运行项…

idea 自定义类注释模板和方法模板,无警告

背景:idea:IntelliJ IDEA 2023.1.3 (Ultimate Edition) 效果:(主要是没无参,不会换行) 类: /** * author sss* date ${DATE} on ${TIME}* desc $NAME*/# 完全复制上面的,删除这一行…

Git #01 操作记录

本篇内容 0. 前期配置1. 仓库1.1 上传本地代码到远程仓库 0. 前期配置 请提前配置好 git 的全局用户名: # xin:账号名 $ git config --global user.name "xin" # xin163.com:账号绑定的邮箱地址 $ git config --global user.emai…

vue注意点:$attrs、$slots!插槽

$attrs 当父组件给子组件传值&#xff0c;子组件并没有接收数据时&#xff0c;此时数据在$attrs中可以拿到&#xff0c;并且如果子组件不需要使用数据&#xff0c;而孙组件需要&#xff0c;则可以直接v-bind"$attrs"传给孙。 <-- 父组件 --> <div><…

目标检测算法:FPN思想解读

目标检测算法&#xff1a;FPN思想解读 说明 ​ FPN算法一种方法/思想&#xff0c;在许多的模型架构中都经常采用&#xff0c;也是提高模型精度的重要方法。 免责申明 ​ 有误写/错写/错误观点/错误解读&#xff0c;或者大家有其它见解&#xff0c;都可以在评论区指出&#xff0…

0719_rasa网站的一些介绍

it’s not a bot, it’s your brand rasa is the leading open generative conversational ai platform for creating and managing ai assistants at scale. learn more talk with sales top enterprises trust rasa american express adobe dell accenture report ho…

scrapy---爬虫界的django

1介绍 scrapy架构 引擎(EGINE)&#xff1a;引擎负责控制系统所有组件之间的数据流&#xff0c;并在某些动作发生时触发事件。大总管&#xff0c;负责整个爬虫数据的流动 调度器(SCHEDULER)用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个U…

Debian 系统安装中文输入法-iTOP3588开发板

Debian 系统烧写完成之后&#xff0c;并没有中文输入功能。本文档将介绍如何安装 ibus pinyin 输入法。 首先安装 fcitx 对应的工具&#xff0c;如下图所示&#xff1a; apt-get install fcitx fcitx-tools fcitx-config* fcitx-frontend* fcitx-module* fcitx-ui-* presage …

uniapp editor组件 如何上传图片

需求&#xff1a;我们在使用uniapp的editor组件时&#xff0c;主要是为了保持输入内容的格式。里面的文字可以有颜色、粗体、排列样式&#xff0c;可以插入图片。就像下面这样。 一、如何处理图片&#xff0c;好让它在 rich-text组件中显示 &#xff1f; 逻辑&#xff1a;我们…

ARP解析MAC地址的全过程(ARP的工作机制)

目录 ARP解析MAC地址的过程&#xff1a; 源码等资料获取方法 以太网环境下&#xff0c;同一个网段的主机之间需要互相知道对方的MAC地址&#xff0c;才能访问。 TCP/IP协议栈从上层到下层的封装过程中&#xff0c;第三层封装需要知道目的IP&#xff0c;第二层封装需要知道目…

计算机毕业论文选题推荐|软件工程|信息管理|数据分析|系列一

文章目录 导文题目导文 计算机毕业论文选题推荐|软件工程|信息管理 (***语言)==使用其他任何编程语言 例如:基于(***语言)门窗账务管理系统的设计与实现 得到:基于JAVA门窗账务管理系统的设计与实现 基于vue门窗账务管理系统的设计与实现 等等 题目 基于requests多线程…

Scala(二)

第2章 变量和数据类型 2.1 注释 Scala注释使用和Java完全一样。 注释是一个程序员必须要具有的良好编程习惯。将自己的思想通过注释先整理出来&#xff0c;再用代码去体现。 1&#xff09;基本语法 &#xff08;1&#xff09;单行注释&#xff1a;// &#xff08;2&#xff0…

动态规划——删除并获得点数

题目链接 leetcode在线oj题——删除并获得点数 题目描述 给你一个整数数组 nums &#xff0c;你可以对它进行一些操作。 每次操作中&#xff0c;选择任意一个 nums[i] &#xff0c;删除它并获得 nums[i] 的点数。之后&#xff0c;你必须删除 所有 等于 nums[i] - 1 和 nums…

spring5源码篇(10)——spring-aop代理过程

spring-framework 版本&#xff1a;v5.3.19 文章目录 1、ProxyFactory1.1、createAopProxy() 创建AopProxy1.2、getProxy() 创建代理对象1.3、JdkDynamicAopProxy#invoke 代理逻辑1.3.1、advised.getInterceptorsAndDynamicInterceptionAdvice() 匹配添加的advisor并转化成所需…

【FAQ】API6低代码开发问题汇总

参考文档&#xff1a; 低代码开发参考文档&#xff1a; 文档中心:使用低代码进行开发 基于景区模板开发元服务&#xff1a; 文档中心:模板简介 使用API6低代码开发遇到的问题汇总情况如下&#xff1a; 1、低代码环境下&#xff0c;如何实现box-shadow阴影效果的配置&#…

K8s核心概念 Controller

K8s核心概念 Controller Kubernetes核心概念 Controller一、pod控制器controller1.1 Controller作用及分类1.2 Deployment1.2.1 Replicaset控制器的功能1.2.2 Deployment控制器的功能1.2.3 Deployment用于部署无状态应用1.2.4 创建deployment类型应用1.2.5 访问deployment1.2.6…

优思学院|六西格玛管理:依据事实的质量管理方式

一个企业的质量管理制度是否规范&#xff0c;也就是质量管理体系是否很完备的问题&#xff0c;要考察管理体系是否还有哪里不尽完美&#xff1f;各部门之间的连系、调整是否能够顺利进行&#xff1f;各自是否达成在质量保证上的任务等&#xff0c;进行质量管理体系的审核&#…

通用文字识别OCR 之实现自动化办公

摘要 随着技术的发展&#xff0c;通用文字识别&#xff08;OCR&#xff09;已经成为现代办公环境中不可或缺的工具之一。OCR技术可以将印刷或手写文本转换为可编辑或可搜索的数字文本&#xff0c;极大地提高了办公效率并实现了自动化办公。本文将深入探讨OCR技术在实现自动化办…

关于你欠缺的NoSQL中的redis和mongoDB

文章目录 前言一、在string list hash结构中&#xff0c;每个至少完成5个命令&#xff0c;包含插入 修改 删除 查询&#xff0c;list 和hash还需要增加遍历的操作命令1、STRING类型2、List类型数据的命令操作&#xff1a;3、举例说明list和hash的应用场景&#xff0c;每个至少一…

经济和行政手段使双高企业降低能耗总量和能耗强度,提高能源利用效率-安科瑞黄安南

摘要 2022年6月29日工信部、发改委、财政部、生态环境部、国资委、市场监管总局六部门联合下发《关于印发工业能效提升行动计划的通知》&#xff08;工信部联节〔2022〕76号&#xff0c;以下简称《行动计划》&#xff09;&#xff0c;主要目的是为了提高工业领域能源利用效率&…