【基础】MQTT -- MQTT 特性:QoS、Retained 消息、LWT 以及 Keepalive

news2024/12/25 9:31:07

MQTT -- MQTT 特性:QoS、Retained 消息、LWT 以及 Keepalive

  • QoS 及其最佳实践
    • MQTT 协议中的 QoS 等级
      • QoS 0
      • QoS 1
        • PUBACK 数据包
      • QoS 2
        • PUBREC 数据包
        • PUBREL 数据包
        • PUBCOMP 数据包
    • 实际的订阅者 QoS
    • QoS 的最佳实践
      • QoS 与会话
      • QoS 的选择
  • Retained 消息
  • LWT 遗嘱消息
  • Keepalive
    • PINGREQ 数据包
    • PINGRESP 数据包
  • MQTT 5 新特性
    • 用户属性
    • 共享订阅
    • 消息过期
    • 重复主题
    • Broker 能力查询
    • 双向 DISCONNECT

QoS 及其最佳实践

MQTT 协议中的 QoS 等级

MQTT 协议最初被用于网络带宽窄、信号不稳定的环境下,因此其设计了一套保证消息稳定传输的机制,这套机制提供了 3 种不同层次的 QoS(Quality of Service):

  • QoS 0:至多一次,at most once;

  • QoS 1:至少一次,at least once;

  • QoS 2:确保一次:exactly once;

QoS 是消息的发送方与消息的接收方之间达成的一个协议:

QoS概述
0发送方发送一条消息,接收方最多能接收到一次。即发送方完成消息发送之后不关心消息发送是否成功。
1发送方发送一条消息,接收方至少能接收到一次。即发送方完成消息发送之后,若发送失败,则继续重发直到接受方接收到消息为止。这种模式下可能会导致接收方收到重复的消息。
2发送方发送一条消息,接收方一定且只能收到一次。即发送方完成消息发送之后,若发送失败,则继续重发直到接收方接收到消息为止,在这一过程中同时保证接收方不会因为消息重传而收到重复的消息。

QoS 0

QoS 0 等级下发送方和接收方之间的一次消息传递流程如下所示:

在这里插入图片描述

发送方将包含消息的 PUBLISH 包发出后,不关心发送结果如何,直接丢弃该 PUBLISH 包,完成一次消息发送。

QoS 1

QoS 1 需要保证消息送达接收方至少一次,因此此处需要一种应答机制,如下所示:

在这里插入图片描述

信息传递过程如下:

  1. 发送方向接收方发送一个包含数据的 PUBLISH 数据包,同时在本地保存该数据包;

  2. 接收方收到 PUBLISH 数据包后,向发送发回复一个 PUBACK 数据包,该数据包的可变头中的包标识与接收到的 PUBLISH 数据包的包标识一致;

  3. 发送方收到回复的 PUBACK 数据包后,根据包标识找到保存在本地的对应的 PUBLISH 数据包并将其丢弃,完成一次消息的发送;

  4. 若发送方在一定时间内未收到 PUBACK 数据包,则将对应的 PUBLISH 数据包的 DUP 标识设置为 1 以表示该包为重发数据包,然后重新发送给接收方,并重复 2、3、4 过程;

PUBACK 数据包

固定头

固定头中数据包类型字段为 4 代表 PUBACK 数据包,该数据包剩余长度字段固定为 2。

在这里插入图片描述

可变头

PUBACK 数据包的可变头包含一个占据两个字节大小的包标识符。

在这里插入图片描述

消息体

PUBACK 数据包不包含消息体。

QoS 2

QoS 2 在 QoS 1 的基础上,进一步保证消息不重复,因此需要更复杂的应答机制,如下:

在这里插入图片描述

QoS 2 采用四段数据交互以保证接收方收到的消息精确一次,因此其开销是最大的,但其安全性是最高的:

  1. 发送方发送 PUBLISH 数据包,并将该数据包保存本地,假设该数据包的包标识符为 Pid;

  2. 接收方收到 PUBLISH 数据包后,将其包标识符 Pid 保存在本地,并返回一个 PUBREC 数据包,该数据包的包标识符为 Pid,无消息体;

  3. 发送方接收到 PUBREC 数据包后,丢弃保存在本地的 PUBLISH 数据包,同时将收到的 PUBREC 数据包保存本地,随后向接收方发送 PUBREL 数据包,该数据包的额包标识符为 Pid。若发送方在一定时间内未收到 PUBACK 数据包,则将对应的 PUBLISH 数据包的 DUP 标识设置为 1 以表示该包为重发数据包,然后重新发送给接收方;

  4. 接收方收到 PUBREL 数据包后,丢弃掉保存的 Pid,并返回一个 PUBCOMP 数据包,该数据包的包标识符为 Pid,无消息体;

  5. 发送方收到对应的 PUBCOMP 数据包后,认为数据包传输完毕,随后丢弃保存本地的 PUBREC 数据包。若接收方在一定的时间内未收到 PUBCOMP 数据包,则会重新发送 PUBREL 数据包;

PUBREC 数据包

固定头

固定头中数据包类型字段为 5 代表 PUBREC 数据包,该数据包剩余长度字段固定为 2。

在这里插入图片描述

可变头

PUBREC 数据包的可变头包含一个占据两个字节大小的包标识符。

在这里插入图片描述

消息体

PUBREC 数据包不包含消息体。

PUBREL 数据包

固定头

固定头中数据包类型字段为 6 代表 PUBREL 数据包,该数据包剩余长度字段固定为 2。

在这里插入图片描述

可变头

PUBREL 数据包的可变头包含一个占据两个字节大小的包标识符。

在这里插入图片描述

消息体

PUBREL 数据包不包含消息体。

PUBCOMP 数据包

固定头

固定头中数据包类型字段为 7 代表 PUBCOMP 数据包,该数据包剩余长度字段固定为 2。

在这里插入图片描述

可变头

PUBCOMP 数据包的可变头包含一个占据两个字节大小的包标识符。

在这里插入图片描述

消息体

PUBCOMP 数据包不包含消息体。

实际的订阅者 QoS

实际上,我们使用 Client 向 Broker 订阅主题时,有时指定的 QoS 和实际的 QoS 不一致,这是因为,在 MQTT 协议中规定:从 Broker 到 Subscriber 的实际 QoS 等于 Publisher 发布消息时指定的 QoS 等级与订阅时指定的 QoS 等级中的较小者

因此,如果使用者希望 Subscriber 至少收到一次消息,那就需要确保 Publisher 和 Subscriber 的 QoS 都不小于 1。

QoS 的最佳实践

QoS 与会话

如果 Client 想要接收离线消息,那么在连接 Broker 时必须指定使用持久会话,这样 Broker 才会存储 Client 在离线期间没有确认接收的且 QoS 大于 1 的消息。

QoS 的选择

  • QoS 0:

    • Client 与 Broker 之间的网络连接非常稳定;

    • 允许丢失部分消息;

    • 不需要接收离线消息;

  • QoS 1:

    • 应用需要接收所有的消息;

    • 应用拥有处理重复消息的能力;

    • 不接受 QoS 2 带来的额外开销(QoS 1 发送消息的速度比 QoS 2 快很多);

  • QoS 2:

    • 应用需要接收所有的消息;

    • 应用不能处理重复的消息;

    • 接受 QoS 2 带来的额外开销;

Retained 消息

Retained 消息是指在 PUBLISH 数据包中 Retain 表示为 1 的消息,Broker 收到消息后,将会为该主题保存该 Retained 消息。当有新的订阅者订阅该主题时,Broker 会将这个消息立即发送给新的订阅者。

Retained 消息存在以下特点:

  • 一个 topic 只能存在一条 Retained 消息,发布新的 Retained 消息将会覆盖旧消息;

  • 若订阅者使用通配符订阅主题,那么该订阅者将会收到所有的匹配主题的 Retained 消息;

  • 只有新的订阅者才能够收到 Retained 消息;

需要注意:Retained 消息与持久会话没有任何关系。Retained 消息针对主题 topic,Broker 为每一个 topic 单独存储;持久会话针对客户端 Client,Broker 为每一个 Client 单独存储。

当 Retained 消息发送到订阅者时,PUBLISH 数据包中的 Retain 字段仍然为 1,订阅者可以根据该字段判断该消息是否是 Retained 消息从而进行相应的处理。

LWT 遗嘱消息

当 Broker 检测到 Client 非正常断开连接时,就会向 Client 遗嘱主题中发布相应的遗嘱消息 LWT(Last Will and Testament)。

遗嘱消息的相关设置是在建立连接时的 CONNECT 数据包中设定的:

  • Will Flag:是否使用 LWT 遗嘱消息;

  • Will Topic:遗嘱主题,不可使用通配符;

  • Will QoS:发布遗嘱消息时的 QoS 等级;

  • Will Retain:遗嘱消息的 Retain 标识;

  • Will Message:遗嘱消息内容;

在以下情况下,Broker 将认为 Client 非常长断开:

  • Broker 检测到底层的 I/O 异常;

  • Client 未能在 Keepalive 的间隔内和 Broker 之间进行消息交互;

  • Client 在关闭底层 TCP 连接前没有发送 DISCONNECT 数据包;

  • Broker 因为协议错误而关闭了与 Client 的连接;

Keepalive

在 MQTT 协议当中,Broker 需要知道 Client 是否非正常的断开,以判断是否发布遗嘱消息。MQTT 是基于 TCP 的一个应用层协议,理论上当 TCP 协议连接断开时会通知上层应用,但 TCP 协议存在半打开连接的问题,在这种状态下一端的 TCP 连接已经失效,但是另一端却无法立即感知,需要很长一段时间才能发现连接已断开。

因此,MQTT 协议设计了 Keepalive 机制。在建立连接时,传输一个以秒为单位的 Keepalive 参数,MQTT 协议规定:在 1.5 倍 Keepalive 时间间隔内,若 Broker 未收到 Client 的任何数据包,则 Broker 就会认为自身与 Client 之间的连接已断开。对于 Client 同理。

为此,MQTT 协议专门设计了一对 PINGREQ\PINGRESP 数据包以满足 Keepalive 的约定和连接状态的侦测。

Keepalive 机制存在以下几种特性:

  • 若在一个 Keepalive 时间间隔内,Client 与 Broker 存在过数据包传输,那么 Client 就没有必要再发送 PINGREQ 数据包了;

  • Keepalive 的数值由 Client 指定,不同的 Client 可以指定不同的 Keepalive 参数;

  • Keepalive 最大值为 18 小时 12 分 15 秒;

  • Keepalive 值设置为 0 表示不使用 Keepalive 机制;

PINGREQ 数据包

当 Client 在一个 Keepalive 时间间隔内没有向 Broker 发送任何数据包时,它应该向 Broker 发送 PINGREQ 数据包以保持连接活性。数据包格式如下:

固定头

固定头中的数据包类型字段值为 12 表示 PINGREQ 数据包,其剩余长度字段固定值为 0。

在这里插入图片描述

可变头

PINGREQ 数据包无可变头。

消息体

PINGREQ 数据包无消息体。

PINGRESP 数据包

当 Broker 收到 Client 发送的 PINGREQ 数据包时,其应该回复一个 PINGRESP 数据包。

固定头

固定头中的数据包类型字段值为 13 表示 PINGRESP 数据包,其剩余长度字段固定值为 0。

在这里插入图片描述

可变头

PINGRESP 数据包无可变头。

消息体

PINGRESP 数据包无消息体。

MQTT 5 新特性

用户属性

MQTT 5 中可以在 PUBLISH、CONNECT 以及带有 Return Code 的数据包中携带一个或者多个用户属性数据。

  • PUBLISH 数据包中所携带的用户属性由发送方的应用定义,随消息被 Broker 转发到消息的订阅方;

  • CONNECT 数据包和 ACKs 数据包也可以携带发送者自定义的用户属性数据;

共享订阅

假设某个主题承载的数据量非常的大,一般情况下我们只能在订阅者中启动多个线程去进行处理以减轻负载。在 MQTT 5.0 中提供了共享订阅的功能,多个 Client 可以共同订阅一个共享主题,发布在该主题的消息就会被均衡的发送给所有的共享订阅 Client,实现负载均衡。

消息过期

MQTT 5.0 包含了消息过期功能,在进行消息发布时可以指定该消息多久后过期,Broker 不会将已过期的离线消息发送给 Client。

重复主题

MQTT 5.0 中,如果将 PUBLISH 数据包的主题名设置为长度为 0 的字符串,那么 Broker 将会使用上一次发布时的主题作为当前消息的主题,以此降低多次发布到统一主题的额外开销。

Broker 能力查询

MQTT 5.0 的 CONNACK 数据包包含了一些预定义的头部数据,用于标识 Broker 支持哪些功能,如下表所示:

预定义头数据类型描述
Retain AvailableBoolean是否支持 Retained 消息
Maximum QoSNumberClient 可用于订阅和发布的最大 QoS
Wildcard avaliableBoolean订阅时是否可以使用通配符主题
Subscription identifiers avaliableBoolean是否支持 Subscription identifier
Shared Subscription avaliableBoolean是否支持共享订阅
Maximum Message SizeNumber可发送的最大消息长度
Server KeepaliveNumberBroker 支持的最大 Keepalive 值

双向 DISCONNECT

MQTT 5.0 中,Broker 主动断开与 Client 的连接时也会发送 DISCONNECT 数据包,双方互发的数据包当中都包含一个 Reason Code 用于标识断开的原因,如下图所示:

Reason Code发送方描述
0Client 或 Broker正常断开连接,不发布遗嘱消息
4Client正常断开连接,但是要求 Broker 发布遗嘱消息
129Client 或 BrokerMQTT 数据包格式错误
135Broker请求未授权
143Broker内部过滤器格式正确,但 Broker 不接收
144Client 或 Broker主题名格式正确,但 Client 或 Broker 不接收
153Client 或 Broker消息体格式不正确
154Broker不支持 Retained 消息
155BrokerQoS 等级不支持
158Broker不支持共享订阅
162Broker订阅时不支持通配符主题名

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

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

相关文章

FPGA_学习_12_IP核_FIFO

FIFO(Frist Input Frist Output),即先入先出,也是一种存储器,一般做数据缓冲。FIFO和 RAM的共同点在于都能存储数据、都有控制写和读的信号;不同点在于 FIFO 没有地址,所以不能任意指定读取某一个数据,数据只能按照数据…

一个女孩从软件测试工程师到主管的成长

说实话,我做测试工作的时间不是很长,学完软件测试工程师的课程后,到现在也就是一年多的时间吧,不过,我愿意自己学习和工作中积累起的这些点滴与大家分享。 如果你想学习自动化测试,我这边给你推荐一套视频…

C语言之程序环境和预处理(1)

本章主要以图片和文字的形式给大家讲解 程序的翻译环境和程序的执行环境 在ANSI C的任何一种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。 第2种是执行环境,它用于实际执行代码 2. 详解编译…

东南亚骑行类目热销品出炉!Shopee/Lazada跨境卖家有哪些优势产品可做?

菲律宾/巴西是Lazada/Shopee骑行品类卖家体量最大的2个站点,新加坡/越南/马来西亚紧随其后. 体量:在东南亚,菲律宾与新加坡对骑行的需求最强烈,其次是越南,三地总订单占总体70%以上,在南美地区&#xff0c…

Revit碰撞检查:Navisworks“复合对象碰撞”的使用

一、Navisworks 中碰撞检查中“复合对象碰撞”有什么用? 通常情况下我们使用 Revit 做好了模型,然后使用 Navisworks这款软件进行碰撞检查等优化工作。因为 Navisworks 相对于 Revit的软件数据要“轻”很多,可以让多专业的模型都在一起导入来进行全专业…

对接口进行限流?

在高并发的情况下,我们可以把消息放入队列,在从队列消费,达到限流的目的。但这里说的限流指的是当我们请求其他服务器接口,防止高并发下把对面服务器压垮,于是对我们要求每秒限制在100QPS。 如果使用springCloud可以用…

准备换工作跳槽面试人一定要看的的18条忠告

1、如果想好要跳槽就别犹豫,不用纠结太多外在因素,很多事情只有去做了才知道。(当然,如果你是非某家公司不可的话,那可以慢慢等待机会) 2、关于跳槽的渠道,主要有四种:直接被公司挖…

测试自动化的演进,从录制回放到对象映射

概要:在短时间的市场化和短期冲刺的文化中,测试人员通过使用测试自动化实践和工具保持同步是至关重要的。本文跟踪从基于脚本的测试与硬编码数据到自动化框架的转变,探索测试自动化的开始和到今天的演变 - 并且可能的未来走向。 今天的软件市…

Qt之QDial选择器

文章目录 前言一、QDial是什么二、操作api信号与槽示例代码总结 前言 Qt是一种流行的跨平台的C GUI应用程序开发框架,用于构建图形用户界面(GUI)和其他桌面应用程序。QDial是Qt框架中的一个小部件,用于创建旋转式的拨号器。本文将介绍如何使用QDial进行…

ChatGLM Efficient Tuning效率调试PEFT

ChatGLM Efficient Tuning 基于 PEFT 的高效 ChatGLM-6B 微调。 [ English | 中文 ] 更新日志 [23/06/05] 现在我们实现了 4 比特的 LoRA 训练(也称 QLoRA)。请尝试使用 --quantization_bit 4 参数进行 4 比特量化微调。(实验性功能&#…

Echarts实现流程图关系图拓扑图

实现如下&#xff0c;可以横着排竖着排都可以 1.先写个div做画布 ref值随意&#xff0c;但是一点要写 <div style"height: 400px;" ref"echartdom"></div> 2.下载echarts 我这边下载的是 "echarts": "^4.9.0",最新版应…

奢侈品回收APP系统开发功能有哪些?

奢侈品售卖回收APP系统开发功能有哪些&#xff1f; 1.回收品牌分类&#xff1a;奢侈品回收APP平台可以将支持回收鉴定的奢侈品品牌及商品进行分类展示&#xff0c;方便用户查看自己的想要出售的是不是平台支持的商品。 2.商品在线检索&#xff1a;客户可以直接按…

STM32F4_红外遥控

目录 1. 红外遥控简介 2. NEC协议 3. 硬件设计 4. 实验程序详解 4.1 main.c 4.2 Remote.c 4.3 Remote.h 1. 红外遥控简介 红外遥控是一种无线、非接触的控制技术。具有抗干扰能力强&#xff0c;信息传输可靠&#xff0c;功耗低&#xff0c;成本低&#xff0c;易实现等优…

深入理解Redis的AOF和RDB持久化机制

Redis的AOF&#xff08;Append-Only File&#xff09;和RDB&#xff08;Redis Database&#xff09;是两种常见的持久化机制&#xff0c;用于将内存中的数据保存到磁盘上&#xff0c;确保数据在Redis重新启动时的持久性。本文将深入介绍AOF和RDB的原理和使用&#xff0c;帮助读…

HQChart实战教程65-自定义手机端分时图tooltip显示数据

HQChart实战教程65-自定义手机端分时图tooltip显示数据 手机端分时图tooltip步骤1. 配置手机端tooltip2. 替换k线tooltip格式化输出函数2. 格式化输出函数说明HQChart插件源码地址完整的demo源码手机端分时图tooltip hqchart手机端内置一个tooltip,显示手势所在K线的信息。默认…

邮件打开率低?来看看这几招提高邮件打开率!

什么是邮件打开率&#xff1f; 邮件打开率&#xff1a;简单来讲就是收件人打开的邮件数占发送邮件总数的百分比。 我们要做的就是如何吸引收件人打开邮件&#xff0c;那可以从以下几个方面来考虑&#xff1a; 1、邮件标题 邮件标题直接向收件人表达了这封邮件是关于什么的&am…

CSS样式优先级怎样划分?【CSS优先级规则】

定义CSS样式时&#xff0c;经常出现两个或更多样式规则应用在同一元素上的情况。此时CSS就会根据样式规则的权重&#xff0c;优先显示权重最高的样式。CSS优先级指的就是CSS样式规则的权重。在网页制作中&#xff0c;CSS为每个基础选择器都指定了不同的权重&#xff0c;方便我们…

【内存问题真的很烦人】linux内存等资源管理 以及 linux内存不足解决办法

linux内存不足解决办法 ///这一部分存在疑问 查看目录下文件夹大小 du -h --max-depth1 看具体哪个文件夹占用内存过高&#xff0c;一般是日志&#xff0c;删除即可。 ///这一部分存在疑问&#xff0c;上面的文件夹可以代表内存吗&#xff1f; 内存不够 top 命令 看内存占用…

Python就业前景如何?三大就业岗位分享

Python是一门面向对象的编程语言&#xff0c;编译速度超快&#xff0c;从诞生到现在已经20来个年头了。Python的排名从去年开始就借助人工智能持续上升&#xff0c;Python的火热&#xff0c;也带动了工程师们的就业热。 据统计&#xff0c;现在初级Python工程师的起薪一般在10…

【 Lucas-Kanade光流法】

这里写目录标题 1.1 Lucas-Kanade光流法1.1 Lucas-Kanade光流法详细步骤&#xff1a; 1.1 Lucas-Kanade光流法 Lucas-Kanade光流法是一种密集光流估计方法&#xff0c;用于计算图像中每个像素的运动向量。它假设在相邻帧之间&#xff0c;像素的灰度值不会发生大的变化&#xf…