遗嘱消息(Will Message)介绍与示例 _ MQTT 5.0 特性详解

什么是 MQTT 遗嘱消息?

在现实世界中,一个人可以制定一份遗嘱,声明在他去世后应该如何分配他的财产以及应该采取什么行动。在他去世后,遗嘱执行人会将这份遗嘱公开,并执行遗嘱中的指示。
在 MQTT 中,客户端可以在连接时在服务端中注册一个遗嘱消息,与普通消息类似,我们可以设置遗嘱消息的主题、有效载荷等等。当该客户端意外断开连接,服务端就会向其他订阅了相应主题的客户端发送此遗嘱消息。这些接收者也因此可以及时地采取行动,例如向用户发送通知、切换备用设备等等。
假设我们有一个传感器监控一个很少变化的值,普通的实现是定期发布最新数值,但更好的实现是仅在数值发生变化时以保留消息的形式发送它。这使得任何新的订阅者总能立即获得当前值,而不必等待传感器再一次发布。不过订阅者也因此没有办法根据是否及时收到消息来判断传感器是否离线。借助遗嘱消息,我们可以立即得知传感器保持活动超时,而且不必总是获取传感器发布的值。

Will Message 还是 Last Will and Testament(LWT)?

在一些博客或者代码中,我们可能会看到 Last Will and Testament 这个名字,或者是它的缩写:LWT。它指的就是 MQTT 中的 Will Message。导致这两种命名共存的原因可能是,MQTT 最早在 3.1 协议规范的摘要中,提到了 Last Will and Testament 这个概念。
虽然 MQTT 在协议的正文部分一直以来都是明确使用 Will Message 这个名字,但目前在用户群体中,这两个名字经常会被混用。
我们无意去纠正其中任何一个用法,我们只是希望不同的名字不会让你感到困惑。

MQTT 遗嘱消息如何运作

客户端在连接时指定遗嘱消息

遗嘱消息在客户端发起连接时指定,它和 Client ID、Clean Start 这些字段一起包含在客户端发送的 CONNECT 报文中。
与普通消息一样,我们可以为遗嘱消息设置主题(Will Topic)、保留消息标识位(Will Retain)、属性(Will Properties)、QoS(Will QoS)和有效载荷(Will Payload)。
image.png
这些字段的用法与它们在普通消息中时完全相同,只是遗嘱消息可用的属性与普通应用消息略有不同,下表列出了它们的具体区别:
image.png
遗嘱消息总是在客户端“死亡”后被发布,在某种意义上,它也是客户端发出的最后一个消息。所以主题别名在遗嘱消息中没有任何意义。
除此之外,遗嘱消息只是多了一个专属属性:Will Delay Interval。它是 MQTT 5.0 为遗嘱消息引入的一个重要改进,我们会在后文中详细介绍它。

服务端在连接意外关闭时发布遗嘱消息

如果客户端在连接时指定了遗嘱消息,那么服务端就会将该遗嘱消息存储在相应的会话中,直到以下任一条件满足时发布它:

  1. 服务端检测到了一个 I/O 错误或者网络故障
  2. 客户端在 Keep Alive 时间内未能通讯
  3. 客户端在没有发送 Reason Code 为 0x00(正常关闭)的 DISCONNECT 报文的情况下关闭了网络连接
  4. 服务端在没有收到 Reason Code 为 0x00(正常关闭)的 DISCONNECT 报文的情况下关闭了网络连接,例如客户端的报文或行为不符合协议要求而被服务端关闭连接。

简单起见,我们可以直接概括为,只要网络连接在服务端没有收到 Reason Code 为 0x00 的 DISCONNECT 报文的情况下关闭,那么服务端都需要发送遗嘱消息。
当客户端完成了预定的工作准备正常下线时,可以发送一个 Reason Code 为 0x00 的 DISCONNECT 报文然后关闭网络连接,避免服务端因此发布遗嘱消息。

Will Delay Interval 与延迟发布

默认情况下,服务端总是在网络连接意外关闭时立即发布遗嘱消息。但是很多时候,网络连接的中断是短暂的,所以客户端往往能够重新连接并继续之前的会话。这导致遗嘱消息可能被频繁地且无意义地发送。
所以 MQTT 5.0 专门为遗嘱消息增加了一个 Will Delay Interval 属性,这个属性决定了服务端将在网络连接关闭后延迟多久发布遗嘱消息,并以秒为单位。
如果没有指定 Will Delay Interval 或者将其设置为 0,服务端将仍然在网络连接关闭时立即发布遗嘱消息。
但如果将 Will Delay Interval 设置为一个大于 0 的值,并且客户端能够在 Will Delay Interval 到期前恢复连接,那么该遗嘱消息将不会被发布。

遗嘱消息与会话

遗嘱消息是服务端会话状态的一部分,当会话结束,遗嘱消息也无法继续单独存在。
但是在遗嘱消息延迟发布期间,会话可能过期,也可能因为客户端在新的连接中设置 Clean Start 为 1 所以服务端需要丢弃之前的会话。
为了避免丢失遗嘱,此时服务端必须发布该遗嘱消息,即便 Will Delay Interval 还没有到期。
所以服务端最终何时发布遗嘱消息,取决于 Will Delay Interval 到期和会话结束这两种情况谁先发生。

MQTT 3.1.1 中的遗嘱消息

在 MQTT 3.1.1 中,只要网络连接在服务端没有收到 DISCONNECT 报文的情况下关闭,服务端都需要发布遗嘱消息。
由于 MQTT 3.1.1 没有 Will Delay Interval,也没有 Session Expiry Interval,所以遗嘱消息总是在网络连接关闭时立即发布。

为什么没有收到遗嘱消息?

遗嘱消息的延迟发布和取消发布让订阅端最终是否会收到遗嘱消息这个问题变得稍显复杂。
我们对所有可能的情况进行了梳理,以便让大家更好地理解:
image.png

  1. 连接意外关闭且 Will Delay Interval 等于 0,遗嘱消息将在网络连接关闭时立即发布
  2. 连接意外关闭且 Will Delay Interval 大于 0,遗嘱消息将被延迟发布,最大延迟时间取决于 Will Delay Interval 与 Session Expiry Interval 谁先到期:
    1. 客户端未能在 Will Delay Interval 或 Session Expiry Interval 到期前恢复连接,遗嘱消息将被发布。
    2. 在 Will Delay Interval 或 Session Expiry Interval 到期前
      1. 客户端指定 Clean Start 为 0 恢复连接,遗嘱消息将不会被发布。
      2. 客户端指定 Clean Start 为 1 恢复连接,遗嘱消息将因为 现有会话结束 而被立即发布。

如果现有网络连接尚未断开,但客户端使用相同 Client ID 发起新的连接,服务端会向现有的网络连接发送一个 Reason Code 为 0x8E(Session Taken Over)的 DISCONNECT 报文然后关闭它。这种情况在网络不佳时非常容易出现,但也属于连接意外关闭。
现在,请思考这样一个问题:如果现有的网络连接的 Session Expiry Interval 等于 0,Will Delay Interval 大于 0,那么当客户端指定 Clean Start 为 0 发起新的网络连接时服务端是否会发送遗嘱消息?
答案是遗嘱消息将在现有的网络连接断开时被立即发布。
当服务端关闭现有的网络连接,由于 Session Expiry Interval 为 0,会话也将立即结束。虽然 Clean Start 设置为 0,但服务端将为新的网络连接创建了一个新的会话。所以遗嘱消息将因为会话结束而被发布,即满足了上面所列情形中的 2.1 而不是 2.2.1。。

遗嘱消息使用技巧

与保留消息一起使用

服务端一旦发布了遗嘱消息,就会将它从会话中删除。如果关心此遗嘱消息的客户端不在线,那么它就错过了这条遗嘱消息。
为了避免这种情况,我们可以将遗嘱消息设置为保留消息,这样遗嘱消息在被发布后,还会以保留消息的形式存储在服务端中,客户端可以在任何时候获取这条遗嘱消息。
如果更进一步,我们还可以实现对指定客户端的状态监控。
让客户端 myclient 在每次连接时都指定一个主题为 myclient/status,有效载荷为 offline 并且设置了 Will Retain 标志的遗嘱消息。每当连接成功,就向主题 myclient/status 发布一个有效载荷为 online 的保留消息。这样,我们就可以随时订阅主题 myclient/status,来获取客户端 myclient 的最新状态。

会话过期通知

通过设置一个大于 Session Expiry Interval 的 Will Delay Interval,服务端可以以遗嘱消息的形式发出会话过期通知。这对于一些更关心会话过期而不是网络连接中断的应用更加有用。即便是主动下线,客户端可以发送一个 Reason Code 为 0x04 的 DISCONNECT 报文要求服务端仍然发送遗嘱消息。

演示

使用 MQTTX

安装并打开 MQTTX,首先向 公共 MQTT 服务器 发起一个客户端连接,在这个连接中我们指定了一个主题为 mqttx_c7f95fdf/status,Payload 为 offline 的遗嘱消息,并且将 Will Delay Interval 设置为 5 秒,Session Expiry Interval 设置为 300 秒。主题使用 Client ID 作为前缀可以有效避免与公共服务器中其他人使用的主题重复:
image.png
新建一个客户端连接,同样连接到公共 MQTT 服务器,然后订阅主题 mqttx_c7f95fdf/status 以接收遗嘱消息:
image.png
接下来,我们让第一个客户端发送一个主题为空,但设置了主题别名的消息,由于我们还未建立主题与主题别名的映射,所以这会让服务端认为客户端的行为不符合协议规范而关闭连接,并且发送遗嘱消息:
image.png
由于设置了 Will Delay Interval,所以我们会在发送消息的 5 秒后在订阅端看到遗嘱消息到达:
image.png

使用 MQTTX CLI

在终端界面,我们可以使用命令行工具 MQTTX CLI 来验证遗嘱消息的行为。接下来,让我们来看看客户端连接在遗嘱消息发布前恢复会发生什么。
首先,在第一个终端窗口中发起连接,并订阅遗嘱主题:

$ client_id="mqttx_"`date | sha256sum | base64 | head -c 8` $ echo ${client_id} mqttx_YzFjZmVj $ mqttx sub -h broker.emqx.io --topic ${client_id}"/status" …  Connecting... ✔  Connected …  Subscribing to mqttx_YzFjZmVj/status... ✔  Subscribed to mqttx_YzFjZmVj/status

然后在第二个终端窗口中建立一个指定了遗嘱消息的客户端连接,并将 Will Delay Interval 设置为 10 秒,Session Expiry Interval 则设置为 300 秒。连接成功后输入 Ctrl+C 退出,这会让客户端不发送 DISCONNECT 报文直接断开网络连接:

$ client_id="mqttx_YzFjZmVj" $ mqttx conn -h broker.emqx.io --client-id ${client_id} --will-topic ${client_id}"/status" --will-message "offline" --will-delay-interval 10 --session-expiry-interval 300 …  Connecting... ✔  Connected ^C

在 10 秒内运行以下命令重连:

$ mqttx conn -h broker.emqx.io --client-id ${client_id} --no-clean --session-expiry-interval 300

第一个终端窗口中的订阅端将不会收到遗嘱消息。
以上是两个非常简单的示例,你可以使用 MQTTX 和免费 MQTT 公共服务器来验证遗嘱消息的更多特性,比如遗嘱消息何时会被发布以及何时不会被发布。
另外,我们在 emqx/MQTT-Features-Example 项目中提供了遗嘱消息的 Python 示例代码,你可以作为参考。

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

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

相关文章

比较不错超声波清洗机有哪些?2024年口碑一绝超声波清洗机推荐

2024年,随着科技的不断进步和消费者需求的日益增长,超声波清洗机在生活中的应用变得越来越广泛。无论是珠宝首饰、眼镜、电子产品还是医疗器械,高效、快速、安全的清洗方式正成为人们追求的目标。超声波清洗机以其独特的清洗方式和卓越的清洗…

让数据在业务间高效流转,镜舟科技与NineData完成产品兼容互认

近日,镜舟科技与NineData完成产品兼容测试。在经过联合测试后,镜舟科技旗下产品与NineData云原生智能数据管理平台完全兼容,整体运行高效稳定。 镜舟科技致力于帮助中国企业构建卓越的数据分析系统,打造独具竞争力的“数据护城河”…

Redis 除了做缓存,还能做什么?

分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。关于 Redis 实现分布式锁的详细介绍,可以看这篇文章:分布式锁详解open in new window 。限流:一般是通过 …

无GPU搭建开源大模型--LLAMA2

在Grok之前,脸书就开源了LLAMA2的大模型,从第三方数据来看Grok各方面都碾压LLAMA2 但如果是初学AI,llama无疑还是一个很好的突破口,在Grok没有到来之前,就让我们先向LLAMA2开刀。 本次介绍如何在无需GPU参与的情况下,在本地部署llama2,方法来自国外大神:Georgi Gergan…

了解常用开发模型 -- 瀑布模型、螺旋模型、增量与迭代、敏捷开发

目录 瀑布模型 开发流程 开发特征 优缺点 适用场景 螺旋模型 开发流程 开发特征 优缺点 适用场景 增量与迭代开发 什么是增量开发?什么是迭代开发? 敏捷开发 什么是敏捷开发四原则(敏捷宣言)? 什么是 s…

基于微信小程序的作业管理系统的设计与实现【附项目源码】分享

基于微信小程序的作业管理系统的设计与实现: 源码地址:https://download.csdn.net/download/qq_41810183/88842836 一、引言 随着移动互联网的普及和微信小程序的广泛应用,教育领域也在积极探索如何利用这些新技术提升教学质量和效率。本需…

工具篇--分布式定时任务springBoot--elasticjob简单使用(1)

文章目录 前言一、elasticjob 介绍:二、elasticjob 使用:2.1 部署zookeeper:2.2 引入库2.2 定义任务:2.3 任务执行:2.4 任务执行控制台输出: 三、elasticjob 启动错误:3.1 KeeperErrorCode Ope…

Infineon_TC264智能车代码初探及C语言深度学习(二)

本篇文章记录我在智能车竞赛中,对 Infineon_TC264 这款芯片的底层库函数的学习分析。通过深入地对其库函数进行分析,C语言深入的知识得以再次在编程中呈现和运用。故觉得很有必要在此进行记录分享一下。 目录 ​编辑 一、代码段分析 NO.1 指向结构体…

《恩爱兔》

恩爱兔 类型:休闲跳跃 视角:2d 乐趣点:通过挑战不同的关卡,战胜困难,乐趣无限,运用智慧跳上高台 时间:2019 个人职责: 所有程序部分的设计开发 此游戏是我和朋友独立开发的一款小游戏…

web作业2024.3.15

案例1: 使用CSS行内式为页面元素引入样式。b) 按照CSS样式规则为3号标题设置成微软雅黑、蓝色、26px字体c) 按照CSS样式规则为段落设置成微软雅黑、红色、28px字体。 七步诗 煮豆燃豆萁, 豆在釜中泣。 本是同根生, 相煎何太急。 案例2…

html--bug

文章目录 html html <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>老师</title><style>body {background-color: #008000;margin: 0px;cursor: none;overflow: hidden;}</style></head><bod…

自动开箱机的工作原理与未来发展趋势

随着物流行业的迅猛发展&#xff0c;自动化、智能化的设备逐渐成为行业的新宠。其中&#xff0c;自动开箱机以其高效、精准的特点&#xff0c;受到了广泛关注。星派将详细解析自动开箱机的工作原理&#xff0c;并探讨其未来发展趋势&#xff0c;带领读者一同走进这一先进技术的…

某赛通电子文档安全管理系统 DecryptApplication 任意文件读取漏洞(2024年3月发布)

漏洞简介 某赛通电子文档安全管理系统 DecryptApplication 接口处任意文件读取漏洞&#xff0c;未经身份验证的攻击者利用此漏洞获取系统内部敏感文件信息&#xff0c;导致系统处于极不安全的状态。 漏洞等级高危影响版本*漏洞类型任意文件读取影响范围>1W 产品简介 …

关系代数-练习

设有一个SPJ数据库&#xff0c;包括4个关系模式S、P、J和 SPJ。 S(SNO, SNAME,STATUS,CITY) ; P(PNO,PNAME,COLOR,WEICHT) ; J(JNO,JNAME,CITY); SPJ(SNO,PNO,JNO,QTY)。 供应商表S由供应商代码(SNO)、供应商姓名(SNAME)、供应商状态(STATUS)、供应商…

MySQL查询学生相关信息

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

OSI(Open Systems Interconnection)模型和TCP/IP模型

OSI模型 OSI模型是一个概念模型&#xff0c;由国际标准化组织&#xff08;ISO&#xff09;在1984年提出&#xff0c;用于促进不同系统间的通信互联。OSI模型将网络通信的过程分为七层&#xff0c;每一层都有其特定的功能&#xff0c;从下至上依次是&#xff1a; 物理层&#x…

如何使用第三方接入淘宝商品详情(主图,详情图)

1、找到可用的API接口&#xff1a;首先&#xff0c;需要找到支持查询商品信息的API接口。这些信息通常可以在电商平台的官方文档或开发者门户网站上找到。 2、注册并获取API密钥&#xff1a;在使用API接口之前&#xff0c;需要注册并获取API密钥。API密钥是识别身份的唯一标识符…

springboot学习(八十六) springboot使用graalvm编译native程序

一、windows环境下 1.下载graalvm的jdk https://injdk.cn/ 下载windows版本 配置java环境变量&#xff0c;配置过程略 2.下载visual Studio Build Tools 下载地址&#xff1a;https://aka.ms/vs/17/release/vs_BuildTools.exe 安装后选择组件&#xff1a; 其中windows S…

Java开发从入门到精通(八):Java的面向对象编程OOP:封装、继承、多态

Java大数据开发和安全开发 &#xff08;一&#xff09;Java的封装1.1 什么是封装1.1.1 封装的设计规范1.1.2 代码层面如何控对象的成员公开或隐藏? 1.2 JavaBean(实体类)1.2.1创建实体类1.2.2 实体类有啥应用场景?1.2.3 实体类总结 1.3 static关键字1.3.1 static修饰成员变量…

AI-逻辑回归模型

&#x1f606;&#x1f606;&#x1f606;感谢大家的支持~&#x1f606;&#x1f606;&#x1f606; 逻辑回归的应用场景 逻辑回归&#xff08;Logistic Regression&#xff09;是机器学习中的 一种分类模型 &#xff0c;逻辑回归是一种分类算法&#xff0c;虽然名字中带有回…