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

Delectate 合宙Luat 昨天


日前,有开发者在交流群中提问:

我按官方的MQTT api,  “遗嘱”效果是反的:掉线时没有消息,上线时反而有消息。

本文就来讲解一下,什么情况使用遗嘱消息,什么情况下会触发遗嘱,以及如何避免它产生的误判。






1


什么是“遗嘱信息”




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

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

典型的“异常情况”有:







MQTT Client 没有上报 close 就和 MQTT Broker 断开连接;


多个 keepalive 周期内没有心跳包上报;


其他相同 ClientID 登录 MQTT Broker 时。



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




2


如何启用“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”(例) 的消息。




3


为什么我没有收到“遗嘱”




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

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







  1. 模块代码错误,或者网络错误等其他情况,或者没有成功连接到 MQTT Broker;

  2. 后台订阅的主题,和模块的遗嘱不是同一个主题;

  3. MQTT Broker 不支持遗嘱;





4

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





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

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









感谢阅览本期内容

欢迎文末留言互动


本期文末最先留言的五位同学

— 将获得合宙商城五折券一张 —


五折券有效期至2月29日

点击公众号菜单“合宙商城”即可使用

2月1日起合宙商城已恢复正常发货









- 粉丝专有福利 -


请由公众号菜单“合宙商城”进入或长按下图识别二维码直达,领取粉丝专有福利↓↓↓




DIY无线电话机 -


- 往期官方教程 -



刘晨旭白话Lua零基础系列教程:

白话Lua教程第一期:初识Lua

白话Lua教程第二期:变量

白话Lua教程第三期:字符串

白话Lua教程第四期:逻辑运算

白话Lua教程第五期:分支判断

白话Lua教程第六期:函数

白话Lua教程第七期:Table



●  Luat系列官方教程1:下载调试工具LuaTools

●  Luat系列官方教程2:控制LED小灯

●  Luat系列官方教程3:Luat程序的基本时序

  Luat系列官方教程4:Luat程序的基本时序

●  Luat系列官方教程5:Socket代码详解

●  Luat系列官方教程6:MQTT代码详解

●  Luat系列官方教程7:串口收发




●  Luat程序如何实现延时运行

●  2G/4G系列模块Lua版本串口功能汇总

●  史上最详细的4G模块驱动安装教程

●  4G模块AT版本PDP使用汇总

●  4G模块AT版本MQTT应用说明

●  4G模块AT版本HTTP应用说明

●  4G模块在Linux 设备上的RNDIS网卡使用

●  4G模块Linux USB驱动以及PPP拨号说明





点亮在看,和更多人一起了解物联网

↓↓↓