日前,有开发者在交流群中提问:
我按官方的MQTT api, “遗嘱”效果是反的:掉线时没有消息,上线时反而有消息。
本文就来讲解一下,什么情况使用遗嘱消息,什么情况下会触发遗嘱,以及如何避免它产生的误判。
顾名思义,就是dying message。该“内定”的消息,是MQTT Client 连接 MQTT Broker 时定义的,Broker 记录下该消息。
其后,不论任何情况下,MQTT Client 与 MQTT Broker 之间的连接发生错误,MQTT Broker都会自动发出该消息到对应的主题。
典型的“异常情况”有:
也就是说,灵活的使用遗嘱,可以更方便的应对设备通信时发生的各种异常情况(如模块掉线、设备被盗、流量卡欠费、网咯信号差等等)。
默认的MQTT例程中,没有遗嘱的相关内容。不过不用担心,MQTT 已有相关API,敬请查阅:
示例代码:
require "mqtt"
module(..., package.seeall)
-- 这里请填写修改为自己的IP和端口
local host, port = "lbsmqtt.airm2m.com", 1884sys.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 下发的内容。
如果长时间测试仍没有收到,那么可能是如下原因:
通常是因为模块端频繁掉线或者重连,MQTT Broker 认为上一个 MQTT Client 已经阵亡了,所以向既定主题发布了对应的消息。
开发者需要根据自己的需求,使用不同的主题和payload,区分遗嘱消息和正常消息,并做好对应的处理。
43 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!