• 欢迎大家分享资料!前往留言板评论即可!

【MQTT】为什么我收不到“遗嘱消息”呢?

合宙 模组资料网 2年前 (2021-05-15) 413次浏览 0个评论 扫描二维码
文章目录[隐藏]
                        日前,有开发者在交流群中提问:</p><blockquote><p><span style="color: rgb(0, 0, 0); font-family: 微软雅黑, 'MS Sans Serif', sans-serif; font-size: 13.3333330154419px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; display: inline !important; float: none; background-color: rgb(255, 237, 196);">我按官方的MQTT api,&nbsp; “遗嘱”效果是反的:掉线时没有消息,上线时反而有消息。</span></p></blockquote><p>本文就来讲解一下,什么情况使用遗嘱消息,什么情况下会触发遗嘱,以及如何避免它产生的误判。

什么是遗嘱

顾名思义,就是dying message。该“内定”的消息,是MQTT Client 连接 MQTT Broker 时定义的,Broker 记录下该消息。

其后,不论任何情况下,MQTT Client 与 MQTT Broker 之间的连接发生错误,MQTT Broker都会自动发出该消息到对应的主题。

典型的“异常情况”有:

  1. MQTT Client 没有上报 close 就和 MQTT Broker 断开连接;
  2. 多个 keepalive 周期内没有心跳包上报;
  3. 其他相同 ClientID 登录 MQTT Broker 时。

也就是说,灵活的使用遗嘱,可以更方便的应对设备通信时发生的各种异常情况(如模块掉线、设备被盗、流量卡欠费、网咯信号差等等)。

如何启用MQTT遗嘱

默认的MQTT例程中,没有遗嘱的相关内容。不过不用担心,MQTT 已有相关API,敬请查阅:

https://wiki.openluat.com/doc/luatApi/#mqttclientclientid-keepalive-username-password-cleansession-will-version

示例代码:

require “mqtt”
module(…, package.seeall)

— 这里请填写修改为自己的IP和端口
local host, port = “lbsmqtt.airm2m.com”, 1884

sys.taskInit(function()
    while true do
        while not socket.isReady() do sys.wait(1000) end
        local mqttc = mqtt.client(misc.getImei(), 300, “username”, “password”, nil,
{qos=0, retain=0, topic=”/willmsg”, payload=misc.getImei()..”device_conn_err”}
, “3.1”)

        while not mqttc:connect(host, port) do sys.wait(2000) end
        if mqttc:subscribe(string.format(“/device/%s/req”, misc.getImei())) then
            if mqttc:publish(string.format(“/device/%s/report”, misc.getImei()), “test publish ” .. os.time()) then
                while true do
                    local r, data, param = mqttc:receive(120000, “pub_msg”)
                    if r then
                        log.info(“这是收到了服务器下发的消息:”, data.payload or “nil”)
                    elseif data == “pub_msg” then
                        log.info(“这是收到了订阅的消息和参数显示:”, data, param)
                        mqttc:publish(string.format(“/device/%s/resp”, misc.getImei()), “response ” .. param)
                    elseif data == “timeout” then
                        log.info(“这是等待超时主动上报数据的显示!”)
                        mqttc:publish(string.format(“/device/%s/report”, misc.getImei()), “test publish ” .. os.time())
                    else
                        break
                    end
                end
            end
        end
        mqttc:disconnect()
    end
end)

— 测试代码,用于发送消息给socket
sys.taskInit(function()
    while true do
        sys.publish(“pub_msg”, “11223344556677889900AABBCCDDEEFF” .. os.time())
        sys.wait(180000)
    end
end)

后端程序的 MQTT Client 订阅 “/willmsg” 这个主题。

当该某 MQTT Client 和 MQTT Broker 连接出错时,Broker 就会自动向 “/willmsg” 主题下发内容为 “868570000000000device_conn_err”(例) 的消息。

为什么我没有收到遗嘱

通常,这是因为测试时,MQTT Client “掉线”时间不够长造成的。测试中,至少要等3个 Keepalive 周期,才会收到 MQTT Broker 下发的内容。

如果长时间测试仍没有收到,那么可能是如下原因:

  1. 模块代码错误,或者网络错误等其他情况,或者没有成功连接到 MQTT Broker;
  2. 后台订阅的主题,和模块的遗嘱不是同一个主题;
  3. MQTT Broker 不支持遗嘱;

为什么我收到了好多次遗嘱

通常是因为模块端频繁掉线或者重连,MQTT Broker 认为上一个 MQTT Client 已经阵亡了,所以向既定主题发布了对应的消息。

开发者需要根据自己的需求,使用不同的主题和payload,区分遗嘱消息和正常消息,并做好对应的处理。


喜欢 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址