MQTT协议详述

news2024/11/17 5:39:31

MQTT

概述

消息队列遥测传输(英语:Message Queuing Telemetry Transport,缩写:MQTT),是基于发布(Publish)/订阅(Subscribe)范式的消息协议,位于TCP/IP协议族的应用层。

MQTT 常现身于物联网项目中,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议。

MQTT 协议规定了两种网络实体:消息代理(中间人)与客户端。消息代理负责接收来自客户端的消息,并转发给目标客户端。

信息的转发是通过主题topic)管理的。发布者有需要分发的数据时,其向连接的消息代理发送携带有数据的控制消息。代理会向订阅此主题的客户端分发此数据。发布者不需要知道订阅者的数据和具体位置;同样,订阅者不需要配置发布者的相关信息。

MQTT 基于 TCP 协议,用于数据传输。变体 MQTT-SN 用于在蓝牙上传输,基于 UDP。

Topic 主题

MQTT topic 是 MQTT 协议中用于识别和路由消息的字符串。它是 MQTT 发布者和订阅者之间沟通的关键要素。在 MQTT 发布/订阅模型中,发布者向特定主题发送消息,而订阅者可以订阅这些主题以接收消息。

MQTT 主题不需要专门花功夫创建,客户端在订阅或者发布时,代理会自动创建;也无需删除,都由代理自动处理。

在这里插入图片描述

主题是一个 UTF-8 编码的字符串,它是 MQTT 协议中消息路由的基础。主题通常被分级,并在级别之间用斜杠/分隔。这类似于 URL 路径,例如:

root/sensor/#
root/sensor/temperature
root/sensor/smoke

虽然协议不禁止以\开头或结尾的主题,但是不建议使用。例如

/root
root/

通配符

这里先普及一下通配符的概念:通配,用适,常用于模糊搜索。即使用特殊的符号来模糊掉具体的关键字,使查找方可以一次性查找模糊后的多个结果。

下面是 MQTT 的通配符介绍:

MQTT 通配符是一种特殊类型的主题,只能用于订阅,不能用于发布。客户端可以订阅通配符主题以接收来自多个匹配主题的消息,无需单独订阅每个主题并减少开销。MQTT 支持两种类型的通配符:+(单级)和#(多级)。

单级通配符+是仅匹配单级主题的通配符,使用单级通配符时,单级通配符必须占据整个级别,例如:

+                            // True
root/sensor/+                // True
root/+/temperature           // True 
root/sensor+                 // False(没有占据整个级别)

如果订阅了root/+/temperature主题,那么:

// 可以收到以下主题的消息
root/sensor/temperature
root/device/temperature
root/any/temperature
// 无法收到以下主题的消息
root/temperature
root/device/sensor/temperature

多级通配符#可匹配主题中任意数量的级别。使用多级通配符时,它必须占据整个级别,并且必须是主题的最后一个字符,例如:

#                  // True(将匹配所有主题)
root/#             // True
root/sensor#       // False(没有占据整个级别)
root/#/sensor      // False(#不在主题字符串的最后一个字节)

如果订阅了root/#主题,那么:

// 可以收到以下主题的消息
root/sensor
root/device
root/sensor/temperature
root/sensor/smoke
// 无法收到以下主题的消息
ruut/sensor

QoS 服务质量

在不稳定的网络环境中,MQTT 设备可能难以仅使用 TCP 传输协议来确保可靠的通信。为了解决这个问题,MQTT包括一个服务质量(QoS)机制,该机制提供了各种消息交互选项,以提供不同级别的服务,以满足用户在不同场景下对可靠消息传递的特定要求。

MQTT 中有 3 个 QoS 级别:(随着QoS级别的提高,消息传递的可靠性也随之提高,但传输过程的复杂性也随之增加)

  • QoS 0,最多一次。(无握手)
  • QoS 1,至少一次。(握手一次)
  • QoS 2,正好一次。(握手两次)

上述握手包括 客户端到代理 和 代理到客户端 的两段,即当 客户甲 以 QoS 1 发布主题 A 时,客户甲 和代理之间进行一次握手;当客户乙 以 QoS 2 订阅主题 A 时,代理与客户乙进行两次握手。

QoS 0

QoS 0 是最低级别的服务,也称为“即发即弃”。在这种模式下,发送方无需等待确认或存储和重新传输消息,因此接收方无需担心接收重复消息。

在这里插入图片描述

为什么 QoS 0 消息会有丢失概率?

QoS 0 消息传输的可靠性取决于 TCP 连接的稳定性。如果连接稳定,TCP可以保证消息的成功下发。但是,如果连接关闭或重置,则存在传输中的消息或操作系统缓冲区中的消息丢失的风险,从而导致 QoS 0 消息传送失败。

QoS 1

QoS 1 引入了确认和重传机制。当发送方收到来自接收方的 PUBACK 数据包时,它认为消息已成功传递。在此之前,发送方必须存储 PUBLISH 数据包以进行可能的重新传输。

发送方使用每个数据包中的数据包 ID 将 PUBLISH 数据包与相应的 PUBACK 数据包进行匹配。这允许发送方识别并从其缓存中删除正确的 PUBLISH 数据包。

在这里插入图片描述

为什么QoS 1 的消息会重复?

在两种情况下,发送方不会收到 PUBACK 数据包。

  1. PUBLISH 数据包未到达接收方。
  2. PUBLISH 数据包到达接收方,但发送方尚未收到接收方的 PUBACK 数据包。

在第一种情况下,发送方将重新传输 PUBLISH 数据包,但接收方将只接收一次消息。

在第二种情况下,发送方将重新传输 PUBLISH 数据包,接收方将再次接收它,从而产生重复的消息(且此消息在接收方看来是新的消息)。

QoS 2

QoS 2 确保消息不会丢失或重复,这与 QoS 0 和 1 不同。但是,它还具有最复杂的交互和最高的开销,因为它要求每个消息传递的发送方和接收方之间至少有两次握手。

在这里插入图片描述

  1. 要启动 QoS 2 消息传输,发送方首先存储并发送具有 QoS 2 的 PUBLISH 数据包,然后等待接收方的 PUBREC 响应数据包。此过程类似于 QoS 1,不同之处在于响应数据包是 PUBREC 而不是 PUBACK。
  2. 收到 PUBREC 数据包后,发送方可以确认接收方已收到 PUBLISH 数据包,并可以删除其本地存储的副本。它不再需要也无法重新传输此数据包。然后,发送方发送一个 PUBREL 数据包,通知接收方它已准备好释放数据包 ID。与 PUBLISH 数据包一样,PUBREL 数据包需要可靠地传送到接收方,因此它被存储以备潜在的重传,并且需要响应数据包。
  3. 当接收方收到 PUBREL 数据包时,它可以确认在此传输流中不会收到其他重新传输的 PUBLISH 数据包。因此,接收方使用 PUBCOMP 数据包进行响应,以发出信号,表明它已准备好将当前数据包 ID 重用于新消息。
  4. 当发送方收到 PUBCOMP 数据包时,QoS 2 流完成。然后,发送方可以使用当前数据包 ID 发送新消息,接收方会将其视为新消息。

为什么 QoS 2 消息不重复?

用于确保 QoS 2 消息不会丢失的机制与用于 QoS 1 的机制相同,因此此处不再讨论。

与 QoS 1 相比,QoS 2 通过添加涉及 PUBREL 和 PUBCOMP 数据包的新进程来确保消息不会重复。

在进一步讨论之前,让我们快速回顾一下 QoS 1 无法避免消息重复的原因。

当我们使用 QoS 1 时,对于接收方,无论响应是否已到达发送方,在发送 PUBACK 数据包后,数据包 ID 都会再次可用。这意味着接收方无法确定其稍后收到的具有相同数据包 ID 的 PUBLISH 数据包是否由于未收到 PUBACK 响应而从发送方重新传输,或者发送方是否在收到 PUBACK 响应后重复使用数据包 ID 发送新消息。这就是 QoS 1 无法避免消息重复的原因。

在这里插入图片描述

在 QoS 2 中,发送方和接收方使用 PUBREL 和 PUBCOMP 数据包来同步数据包 ID 的释放,从而确保发送方在重新传输消息还是发送新消息方面达成共识。这是避免 QoS 1 中可能出现重复消息问题的关键。

在这里插入图片描述

在 QoS 2 中,允许发送方在接收接收方接收 PUBREC 数据包之前重新传输 PUBLISH 数据包。发送方收到 PUBREC 并发送 PUBREL 数据包后,将进入数据包 ID 释放过程。发送方在收到来自接收方的 PUBCOMP 数据包之前,无法重新传输 PUBLISH 数据包或发送具有当前数据包 ID 的新消息。

在这里插入图片描述

因此,接收方可以使用 PUBREL 数据包作为边界,并将在其之前到达的任何 PUBLISH 数据包视为重复数据包,将在其之后到达的任何 PUBLISH 数据包视为新数据包。这使我们能够在使用 QoS 2 时避免协议级别的消息重复。

keep alive 保活

MQTT 协议托管在 TCP 协议之上,TCP 协议是面向连接的,并在两个连接方之间提供稳定有序的字节流。但是,在某些情况下,TCP 可能会出现半连接问题。半连接是指在一侧断开或未建立连接,而另一侧的连接仍保持连接。在这种情况下,半连接方可能会不断发送数据,而数据显然永远不会到达另一端。为了避免半连接导致的通信黑洞,MQTT协议提供了Keep Alive机制(以下统称保活机制),允许客户端和MQTT服务器判断是否存在半连接问题,并关闭相应的连接。

当客户端与代理创建连接时,通过将连接请求协议包中的Keep Alive变量标头字段设置为非零值,表示客户端发送的连续两个MQTT数据包的时间间隔最大值。如果客户端发送的 Keep Alive 字段不存在值,则代理不会启动保活机制。在 MQTT5 中,引入了 Server Keep Alive 的概念,即由代理来设置这个保活时间。

保活过程

客户端进程

建立连接后,客户端需要确保其发送的任意两个 MQTT 协议报文之间的间隔不超过 Keep Alive 值。如果客户端处于空闲状态并且没有要发送的数据包,则可以改为发送 PINGREQ 协议数据包。

当客户端发送 PINGREQ 数据包时,代理必须返回 PINGRESP 数据包。如果客户端在可靠时间内没有收到来自服务器的 PINGRESP 报文,则表示连接已中断,代理处于离线状态,或者出现网络故障,客户端应关闭连接。

代理流程

建立连接后,如果代理在 Keep Alive 时间的 1.5 倍内没有收到来自客户端的任何报文,则会认为与客户端的连接存在问题,并且代理将与客户端断开连接。

如果代理收到来自客户端的 PINGREQ 协议报文,则需要回复 PINGRESP 协议报文进行确认。

Will Message 遗言

Keep Alive 通常与 Will Message 结合使用,它允许设备在发生意外离线事件时及时通知其他客户端。

保留消息

如果消息代理接受到某个主题上的消息,且这个主题没有任何订阅,那么代理就会丢弃之,除非发布者将其标记为保留消息retained message)。

共享订阅

共享订阅是 MQTT 5.0 的一项特性,MQTT 5.0 是一种在多个订阅者之间实现负载均衡的订阅方式。共享订阅的主题以 $share 开头。

同非共享订阅一样,共享订阅包含一个主题过滤器和订阅选项,唯一的区别在于共享订阅的主题过滤器格式必须是 $share/{ShareName}/{filter} 这种形式。这几个的字段的含义分别是:

  • $share 前缀表明这是一个共享订阅的主题
  • {ShareName} 是一个不包含 “/”, “+” 以及 “#” 的字符串。订阅会话通过使用相同的 {ShareName} 表示位于同一个共享组,匹配该订阅的消息每次只会发布给一个共享组中的其中一个会话(有点绕,看后面例子会更清晰)
  • {filter} 即非共享订阅中的主题过滤器,如root/sensor/smoke

假设某系统有四个订阅者A B C D,一个发布者X;

其中 A和B 共处共享组 team1,C和D 共处共享组 team2;

A B C D 都订阅主题topic/msg

                                           $share/team1/topic/msg  +---+
                                          +----------------------->| A |
                                         /                         +---+
                                        /
                                       /   $share/team1/topic/msg  +---+
                                      /  +------------------------>| B |
+-------+   topic/msg       +--------+  /                          +---+
|   X   |   ----------->    | Broker |
+-------+   "hello"         +--------+  \  $share/team2/topic/msg  +---+
                                      \  +------------------------>| C |
                                       \                           +---+
                                        \
                                         \  $share/team2/topic/msg +---+
                                          +------------------------| D |
                                                                   +---+

结果分析:

X向主题topic/msg发送了一个消息 “hello”,

A和B其中随机一个会收到 “hello”,因为他俩订阅了共享组team1的topic/msg

C和D其中随机一个会收到 “hello”,因为他俩订阅了共享组team2的topic/msg

代理只会向共享组team1发送一次"hello";同理 team2 也只发一次。

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

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

相关文章

qt QTreeView的简单使用(多级子节点)

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);setWindowTitle("QTreeView的简单使用");model new QStandardItemModel;model->setHorizontalHeaderLabels(QStringList() << "left&q…

解决OneDrive “拒绝访问文件” 问题

问题描述&#xff1a; 在尝试将其他文件拖入oneDrive或是打开OneDrive中的文件时。出现如下报错&#xff1a; 拒绝访问文件 无法访问XXXXXXX中的文件。可能已移动或删除了此文件&#xff0c;或者受制于文件权限而不能访问。 ERR_ACCESS_DENIED 解决办法&#xff1a; 1. 找到O…

统计学三学习笔记

一&#xff0c;t分布 二&#xff0c;置信区间 最终要用② n越大&#xff0c;s越小&#xff0c;置信区间越小 三&#xff0c;配对样本t检验 假如有两个族群&#xff1a;

2024-07-01_外语学习

文章目录 前言1、Los Angeles至于单个los 是什么意思&#xff1f;我们可以逐词翻译这个西班牙语句子 2. Extraneous non-props attributes (style) were passed to component but could not be automatically inherited because component renders fragment or text root nodes…

【UE5.1】Chaos物理系统基础——02 场系统的应用

目录 步骤 一、运用临时场&#xff08;外部张力&#xff09;破裂几何体集 二、使用构造场固定几何体集 步骤 在上一篇中&#xff08;【UE5.1】Chaos物理系统基础——01 创建可被破坏的物体&#xff09;我们已经创建了可被破碎的几何体集&#xff0c;在最后我们防止几何体集…

python(6)numpy的使用详细讲解

在numpy中&#xff0c;最基本的数据结构是数组&#xff0c;因此我们首先需要了解如何创建一个数组。numpy提供了多种数组创建方法&#xff0c;包括从列表或元组创建、从文件中读取数据、使用特定函数创建等。下面是一些常用的创建方法&#xff1a; 一、创建数组 1. 从列表或元…

【YOLOv5/v7改进系列】更换损失函数为CIOU、GIOU、SIOU、DIOU、EIOU、WIOUv1/v2/v3、Focal C/G/S/D/EIOU等

一、导言 在目标检测任务中&#xff0c;损失函数的主要作用是衡量模型预测的边界框&#xff08;bounding boxes&#xff09;与真实边界框之间的匹配程度&#xff0c;并指导模型学习如何更精确地定位和分类目标。损失函数通常由两部分构成&#xff1a;分类损失&#xff08;用于…

叮!云原生虚拟数仓 PieCloudDB Database 动态包裹已送达

第一部分 PieCloudDB Database 最新动态 支持动态配置查询簇 PieCloudDB 最新内核版本 v2.14.0 新增动态配置查询簇功能。PieCloudDB 动态配置查询簇功能实现可伸缩的并行化查询&#xff0c;可提升单个查询并行使用底层资源的能力&#xff0c;同时加快查询响应速度。 动态配…

【论文阅读】-- TimeNotes:时间序列数据的有效图表可视化和交互技术研究

TimeNotes: A Study on Effective Chart Visualization and Interaction Techniques for Time-Series Data 摘要1 介绍和动机2 文献2.1 时间序列数据探索2.1.1 数据聚合2.1.2 基于透镜2.1.3 基于布局 3 任务和设计3.1 数据3.2 领域表征3.3 探索、分析和呈现 4 TimeNotes4.1 布局…

制造型企业生产管理的技巧,你都用过哪些?

作为管理者&#xff0c;一谈到生产管理&#xff0c;你可能会想到很多生产过程中的问题&#xff1a;订单准交率不高、计划达成率不高、生产效率低、再制品太多、生产周期长等等一系列问题&#xff1b;如果你不仅仅是一名管理者&#xff0c;你还是一名企业主&#xff0c;你甚至经…

计算机图形学入门22:双向反射分布函数(BRDF)

1.定义 所谓BRDF&#xff08;Bidirectional Reflectance Distribution Function&#xff0c;双向反射分布函数&#xff09;&#xff0c;指的是从辐射度量学的角度去理解光线的反射&#xff0c;如下图所示。 所谓反射就是一个点从ωi方向发出的Radiance转化为dA接收到的功率E&am…

【存储】相关内容

【存储】相关内容 1. 存储类型1. 块存储2. 文件存储3. 对象存储4. 三种存储类型对比 2. 常见的存储分类1. DAS2. SAN3. NAS4. 存储分类分析比较 3. 一些存储的概念1. LUN2. volume3. HBA4. iSCSI 1. 存储类型 块存储和文件存储是我们比较熟悉的两种主流的存储类型&#xff0c;…

可燃气体报警器检定规程最新标准:行业规范与监管要求的解读

随着工业、商业和民用领域对安全要求的不断提高&#xff0c;可燃气体报警器作为预防火灾和爆炸事故的重要设备&#xff0c;其准确性和可靠性受到了广泛关注。为了保障可燃气体报警器的正常运行和有效使用&#xff0c;制定并执行最新的检定规程至关重要。 在这篇文章中&#xf…

论文笔记:MobilityGPT: Enhanced Human MobilityModeling with a GPT mode

1 intro 1.1 背景 尽管对人类移动轨迹数据集的需求不断增加&#xff0c;但其访问和分发仍面临诸多挑战 首先&#xff0c;这些数据集通常由私人公司或政府机构收集&#xff0c;因此可能因泄露个人敏感生活模式而引发隐私问题其次&#xff0c;公司拥有的数据集可能会暴露专有商…

RabbitMQ消息可靠性等机制详解(精细版三)

目录 七 RabbitMQ的其他操作 7.1 消息的可靠性(发送可靠) 7.1.1 confim机制(保证发送可靠) 7.1.2 Return机制(保证发送可靠) 7.1.3 编写配置文件 7.1.4 开启Confirm和Return 7.2 手动Ack(保证接收可靠) 7.2.1 添加配置文件 7.2.2 手动ack 7.3 避免消息重复消费 7.3.…

【Python爬虫】Python爬取喜马拉雅,爬虫教程!

一、思路设计 &#xff08;1&#xff09;分析网页 在喜马拉雅主页找到自己想要的音频&#xff0c;得到目标URL&#xff1a;https://www.ximalaya.com/qinggan/321787/ 通过分析页面的网络抓包&#xff0c;最终的到一个比较有用的json数据包 通过分析&#xff0c;得到了发送json…

《梦醒蝶飞:释放Excel函数与公式的力量》7.3 RIGHT函数

第七章&#xff1a;文本处理函数 第三节&#xff1a;7.3 RIGHT函数 7.3.1. RIGHT函数简介 RIGHT函数用于从文本字符串的末尾提取指定数量的字符&#xff0c;适合在需要从文本中提取特定后缀或处理固定格式的数据时使用。 语法&#xff1a; RIGHT(text, [num_chars]) text…

1974Springboot医院远程诊断管理系统idea开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot医院远程诊断管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库…

提高软件测试效率的7个技巧

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 软件测试是保证软件质量的重要环节&#xff0c;也是软件开发过程中不可或缺的一部分。 实际工作…