背景导入

让我们来看一下这个场景:

你有一个温度传感器,它每三个小时向一个 Topic 发布当前的温度。那么问题来了,有一个新的订阅者在它刚刚发布了当前温度之后订阅了这个主题,那么这个订阅端什么时候能才能收到温度消息?

对的,它必须等到三个小时以后,温度传感器再次发布消息的时候才能收到。在这之前,这个新的订阅者对传感器的温度数据一无所知。

怎么来解决这个问题呢?

这个时候就轮到 Retained 消息出场解决这个问题了。Retained 消息是指在 PUBLISH 数据包中 Retain 标识设为 1 的消息,Broker 收到这样的 PUBLISH 包以后,将保存这个消息,当有一个新的订阅者订阅相应主题的时候,Broker 会马上将这个消息发送给订阅者。

Retained 消息

Retain 消息有以下一些特点:

  • 一个 Topic 只能有 1 条 Retained 消息,发布新的 Retained 消息将覆盖老的 Retained 消息;
  • 如果订阅者使用通配符订阅主题,它会收到所有匹配的主题上的 Retained 消息;
  • 只有新的订阅者才会收到 Retained 消息,如果订阅者重复订阅一个主题,也会被当做新的订阅者,然后收到 Retained 消息;
  • Retained 消息发送到订阅者时,消息的 Retain 标识仍然是 1,订阅者可以判断这个消息是否是 Retained 消息,以做相应的处理。

注意:Retained 消息和持久性会话没有任何关系,Retained 消息是 Broker 为每一个 Topic 单独存储的,而持久性会话是 Broker 为每一个 Client 单独存储的。

如果你想删除一个 Retained 消息也很简单,只要向这个主题发布一个 Payload 长度为 0 的 Retained 消息就可以了。

那么开头我们提到的那个场景的解决方案就很简单了,温度传感器每 3 个小时发布当前的温度的 Retained 消息,那么无论新的订阅者什么时候进行订阅,它都能收到温度传感器上一次发布的数据。

LWT(最后遗嘱)

LWT 全称为 Last Will and Testament,也就是我们在连接到 Broker 时提到的遗嘱,包括遗嘱主题、遗嘱 QoS、遗嘱消息等。

顾名思义,当 Broker 检测到 Client 非正常地断开连接的时候,就会向遗嘱主题里面发布一条消息。遗嘱相关的设置是在建立连接的时候,在 CONNECT 数据包里面的 Variable header(可变头与) Payload(有效载荷) 中 指定的。

  • Will Flag:是1否0使用 LWT
  • Will Topic:遗嘱主题名,不可使用通配符(在 CONNECT报文中的 有效载荷 中 设置)
  • Will Qos:发布遗嘱消息时使用的 QoS 等级,如果遗嘱标志(Will Flag)被设置为0,遗嘱QoS也必须设置为0(0x00)
  • Will Retain:遗嘱消息的 Retain 标识
  • Will Message:遗嘱消息内容(在 CONNECT报文中的 有效载荷 中 设置)

Broker 在以下情况下认为 Client 是非正常断开连接的:

  • Broker 检测到底层的 I/O 异常;
  • Client 未能在 Keep Alive 的间隔内和 Broker 之间有消息交互;
  • Client 在关闭底层 TCP 连接前没有发送 DISCONNECT 数据包;
  • Broker 因为协议错误关闭和 Client 的连接,比如 Client 发送了一个格式错误的 MQTT 数据包。

如果 Client 通过发布 DISCONNECT 数据包断开连接,这个属于正常断开连接,不会触发 LWT 的机制,同时,Broker 还会丢弃掉这个 Client 在连接时指定的 LWT 参数。

根据遗嘱的属性和触发机制,我们不难看出,遗嘱常用于获取设备的连接状态。

注意,设置好遗嘱以后还不够(因为你只要订阅者一启动就会收到遗嘱消息,如果此时发布者已经在线,会导致不准确),
所以,还需要在设备成功连接MQTT的时候主动发个消息,发送的主题必须和遗嘱的主题相同,设置好消息的 retain 属性,让其自动纠正过来。

MQTT 协议学习:Retained(保留消息) 与 LWT(最后遗嘱)的更多相关文章

  1. MQTT 协议学习: 总结 与 各种定义的速查表

    背景 经过几天的学习与实操,对于MQTT(主要针对 v3.1.1版本)的学习告一段落,为了方便日后的查阅 本文链接:<MQTT 协议学习: 总结 与 各种定义的速查表> 章节整理 MQTT ...

  2. MQTT 协议学习:004-MQTT建立通信与 CONNECT 、CONNACK 报文

    背景 上一讲 MQTT 协议学习:通信报文的构成介绍了在MQTT通信中,各报文的通信流程:从本讲开始,我们开始介绍实际中使用的报文,以及它们的组成. CONNECT - 连接请求 报文 客户端到服务端 ...

  3. MQTT 协议学习:005-发布消息 与 对应报文 (PUBLISH、PUBACK、PUBREC、PUBREL)

    背景 当有订阅者订阅了有关的主题以后,通过发布消息的消息的动作,可以让订阅者收到对应主题的消息. 根据不同的QoS 等级,通信的动作也略有不同. PUBLISH – 发布消息 报文 PUBLISH控制 ...

  4. MQTT 协议学习:002- 通信报文的构成

    背景 之前工作中参与有关协议调试的时候,发现对于协议帧的解析是比较重要的. 参考:<MQTT协议 -- 消息报文格式>.<基于STM32实现MQTT>.<MQTT协议从服 ...

  5. MQTT协议学习笔记

    1.前沿 万物联网的时代即将到来,物联网也由当初的概念开始进一步落实.随着无线网络技术飞速发展,各种设备都可以连接网络,实现远程控制.例如智能家居最近非常火爆,智能插座.智能LED灯.智能摄像头等.在 ...

  6. MQTT 协议学习: QoS等级 与 会话

    背景 QoS 等级 与 通信的流程有关,直接影响了整个通信.而且篇幅比较长,所以我觉得应该单独拎出来讲一下. 概念 QoS 代表了 服务质量等级. 设置上,由2 位 的二进制控制,且值不允许为 3(0 ...

  7. MQTT 协议学习:006-订阅主题 与 对应报文(SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK)

    背景 之前我们提到了怎么发布消息对应的报文:现在我们来看,订阅一个主题的报文是怎么样的. SUBSCRIBE - 订阅主题 客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅.每个订阅注册 ...

  8. MQTT协议学习总结

    一.MQTT介绍 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通 ...

  9. MQTT协议学习研究 & Mosquitto简要教程(安装和使用)

    若初次接触MQTT协议,可先理解以下概念: [MQTT协议特点]——相比于RESTful架构的物联网系统,MQTT协议借助消息推送功能,可以更好地实现远程控制. [MQTT协议角色]——在RESTfu ...

  10. MQTT协议学习及实践(Linux服务端,Android客户端的例子)

    前言 MQTT(Message Queuing Telemetry Transport),是一个物联网传输协议,它被设计用于轻量级的发布/订阅式消息传输,旨在为低带宽和不稳定的网络环境中的物联网设备提 ...

随机推荐

  1. 【PAT甲级】1030 Travel Plan (30 分)(SPFA,DFS)

    题意: 输入N,M,S,D(N,M<=500,0<S,D<N),接下来M行输入一条边的起点,终点,通过时间和通过花费.求花费最小的最短路,输入这条路径包含起点终点,通过时间和通过花费 ...

  2. [POI 2014]PTA-Little Bird

    Description 题库连接 给你 \(n\) 棵树,第 \(i\) 棵树的高度为 \(d_i\).有一只鸟从 1 号树出发,每次飞跃不能超过 \(k\) 的距离.若飞到下一棵树的高度大于等于这一 ...

  3. C++11常用特性介绍——auto类型修饰符

    1.C++11常用特性介绍 从本篇开始介绍C++11常用特性,大致分:关键字及新语法.STL容器.多线程.智能指针内存管理,最后讲一下std::bind和std::function 二.关键字和新语法 ...

  4. 「CF438D The Child and Sequence」

    一道CF线段树好题. 前置芝士 线段树:一个很有用数据结构. 势能分析:用来证明复杂度,其实不会也没什么关系啦. 具体做法 不难发现,对于一个数膜一个大于它的数后,这个数至少减少一半,每个数最多只能被 ...

  5. in comment after two dashes (--) next character must be > not - (position: START_TAG seen ...

    Error executing Maven. in comment after two dashes (--) next character must be > not - (position: ...

  6. 个人相关API - 行驶方向判断函数

    calculateDrivingDirection(newCoordinates,oldCoordinates){ let o = { direction: '', deviation:null, i ...

  7. Windows的本地时间(LocalTime)、系统时间(SystemTime)、格林威治时间(UTC-Time)、文件时间(FileTime)之间的转换

    今天处理了一个Bug,创建历史数据时脚本函数的起始时间不赋值或者赋0值时,计算引擎推给历史库的UTC时间为-288000000000,一开始以为是bug,经过分析后发现不赋值默认给起始时间赋0值,而此 ...

  8. 在ubuntu中,通过代理服务器访问网络

    一.临时设置代理服务的方式 export http_proxy=http://yourproxyaddress:proxyport 这种方式在你退出当前的shell之前,会影响到所有网络命令,包括wg ...

  9. 阿里云服务器ubantu创建新用户登录显示问题

    在root用户下输入:vi /etc/passwd,找到添加的用户,在后面加上/bin/bash 重新登录即回复正常

  10. 本周总结(19年暑假)—— Part4

    日期:2019.8.4 博客期:110 星期日 最近还是学开车,听了父母的建议,为了将来的考研,我开始对基本学课进行复习