Mqtt Retained Message(保留消息)

Retained Message:

保留消息定义

  如果PUBLISH消息的RETAIN标记位被设置为1,则称该消息为“保留消息”;
  Broker会存储每个Topic的最后一条保留消息及其Qos,当订阅该Topic的客户端上线后,Broker需要将该消息投递给它。

A retained message is a normal MQTT message with the retained flag set to true. The broker will store the last retained message and the corresponding QoS for that topic Each client that subscribes to a topic pattern, which matches the topic of the retained message, will receive the message immediately after subscribing. For each topic only one retained message will be stored by the broker.

保留消息作用

  可以让新订阅的客户端得到发布方的最新的状态值,而不必要等待发送。

A retained message makes sense, when newly connected subscribers should receive messages immediately and shouldn’t have to wait until a publishing client sends the next message. This is extremely helpful when for status updates of components or devices on individual topics. For example the status of device1 is on the topic myhome/devices/device1/status, a new subscriber to the topic will get the status (online/offline) of the device immediately after subscribing when retained messages are used. The same is true for clients, which send data in intervals, temperature, GPS coordinates and other data. Without retained messages new subscribers are kept in the dark between publish intervals. So using retained messages helps to provide the last good value to a connecting client immediately.

保留消息的删除

  1. 方式1:发送空消息体的保留消息;
  2. 方式2:发送最新的保留消息覆盖之前的(推荐);

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

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

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

怎么来解决这个问题呢?

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

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 消息,那么无论新的订阅者什么时候进行订阅,它都能收到温度传感器上一次发布的数据。

8.2 代码实践:发布和接收 Retained 消息

在这里我们编写一个发布 Retained 消息的发布者,和一个接受消息的订阅端,订阅端在接收消息的时候将消息的 Retain 标识和内容打印出来。

完整的代码 publish_retained.js 如下:

var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://iot.eclipse.org', {
    clientId: "mqtt_sample_publisher_1",
    clean: false
})

client.on('connect', function (connack) {
    if(connack.returnCode == 0){
        client.publish("home/2ndfloor/201/temperature", JSON.stringify({current: 25}), {qos: 0, retain: 1}, function (err) {
            if(err == undefined) {
                console.log("Publish finished")
                client.end()
            }else{
                console.log("Publish failed")
            }
        })
    }else{
        console.log(`Connection failed: ${connack.returnCode}`)
    }

})

完整的代码 subscribe_retained.js 如下:

var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://iot.eclipse.org', {
    clientId: "mqtt_sample_subscriber_id_chapter_8",
    clean: false
})

client.on('connect', function (connack) {
    if(connack.returnCode == 0) {
        if (connack.sessionPresent == false) {
            console.log("subscribing")
            client.subscribe("home/2ndfloor/201/temperature", {
                qos: 0
            }, function (err, granted) {
                if (err != undefined) {
                    console.log("subscribe failed")
                } else {
                    console.log(`subscribe succeeded with ${granted[0].topic}, qos: ${granted[0].qos}`)
                }
            })
        }
    }else {
        console.log(`Connection failed: ${connack.returnCode}`)
    }
})


client.on("message", function (_, message, packet) {
    var jsonPayload = JSON.parse(message.toString())
    console.log(`retained: ${packet.retain}, temperature: ${jsonPayload.current}`)
})

我们首先运行 node publish_retained.js,再运行 node subscribe_retained.js,会得到以下输出:

retained: true, temperature: 25

可见我们在 Publisher 发布之后再订阅主题也能收到 Retained 消息。

然后我们再运行一次 node publish_retained.js,在运行 subscribe_retained.js 的终端会有以下输出:

retained: false, temperature: 25

Broker 收到 Retained 消息以后,只是保存这个消息,然后按照正常的转发逻辑转发给订阅者,所以对订阅者来说,这个是一个普通的 MQTT 消息,所以 Retain 标识为 0。

然后 Ctrl+C 关闭掉 subscribe_retained.js,然后重新运行,终端不会有任何输出,可见 Retained 消息只对新订阅的订阅者有效。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值