MQTT
简介
- 优势:长连接,低带宽,高可靠。
- 实用场景:需要服务器下发消息给设备,需要及时收到。例如,远程开关,充电桩等
几个重要名词
- username用户名,password密码,clientid用户标识,mqtt可以通过前两个参数保证连接的安全,通过clientid确保设备唯一性。
- qos消息质量,分为0,1,2三个等级,分别表示只发一次,至少收到一次和只收到一次,通过qos可以根据数据的重要性灵活选择发送方式以节省带宽和保证数据可靠。例如不重要的数据采集可使用qos0只发一次不关心服务器是否收到,重要的消息通过qos1确保能收到,付款信息危险设备开关等场景使用qos2保证数据到达的同时且不重复。
- host主机,port端口,mqtt需要连接的服务器参数。host可以说ip或者域名。
- topic主题,根据主题区别消息类型和来源,主要用来分类数据。同时mqtt是发布订阅模型,topic是发布和订阅者通信的重要通道。
- payload消息内容,发布和订阅的具体数据。
- retain保留消息,保留消息是一条将保留标志(retained flag)置为true的普通MQTT消息。broker会针对主题依照QoS级别保留最后一条保留消息,当订阅者订阅主题时会立即收到保留消息。broker仅为每个主题保留一条保留消息。
API说明
mqtt的API在luat lib有做封装,建议直接用lib的API接口。
API接口 | 描述 |
---|---|
mqtt.client() | 创建一个mqtt client实例 |
mqttc:connect() | 连接mqtt服务器 |
mqttc:subscribe() | 订阅主题 |
mqttc:unsubscribe() | 取消订阅主题 |
mqttc:publish() | 发布一条消息 |
mqttc:receive() | 接收消息 |
mqttc:disconnect() | 断开与服务器的连接 |
详细的API介绍见mqtt API章节
实现流程
- 创建任务
通过sys.taskInit() 创建一个协程。 - 等待网络就绪
采用socket.isReady()这个接口阻塞操作,程序运行到这里会进入等待直到底层网络注册完成,网络状态就绪,否则等待至超时。 - 创建一个实例
luat的mqtt操作首先要创建一个实例使用mqtt.client(clientId, keepAlive, username, password, cleanSession, will, version)创建一个实例。 - 连接服务器
然后使用mqttc:connect(host, port, transport, cert, timeout)连接服务器。 - 订阅主题
使用mqttc:subscribe(topic, qos)订阅主题。 - 发布一条消息
使用mqttc:publish(topic, payload, qos, retain)发布一条消息。 - 接收消息
使用mqttc:receive(timeout, msg)接收消息。 - 断开与服务器的连接
当网络被断开时使用mqttc:disconnect()断开与服务器的连接。
示例
相关实例程序在脚本库的demo\mqtt文件夹下,包含sendInterruptRecv,sendWaitRecv实例,可以根据实际需要选择demo进行研究。以下是sendWaitRecv实例代码
开机与连接网络
-- 这里请填写修改为自己的IP和端口
local host, port = "lbsmqtt.airm2m.com", 1884
-- 测试MQTT的任务代码
sys.taskInit(function()
while true do
while not socket.isReady() do sys.wait(1000) end
local mqttc = mqtt.client(misc.getImei(), 300, "user", "password")
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(100)
end
end)
常见问题
连接服务器失败
- 检查下模块信号、网络注册、网络附着、PDP激活状态
- 检查下SIM卡是否欠费【4G模块有一种欠费表现:无法注册4G网络,可以注册2G网络】
- 使用mqtt.fx,连接服务器确认一下是否可以连接成功,排除服务器故障
- 部分国外的开源项目提供免费的MQTT代理服务器,因为网络的原因,国内存在严重的延迟或者丢包现象,导致程序运行出现问题,此现象在AT开发时影响严重
最多同时支持多少个连接
10个。
如何实现掉线自动重连
参考mqtt demo,实现自动重连即可
频繁掉线是什么原因
- 检查下是否存在代码逻辑错误,导致异常
- 检查下是否不断重启,导致异常
- 检查下服务器网络是否稳定,不要用内网穿透方式搭建服务器
- 检查下使用环境是否网络覆盖不好,例如车库、地下、电梯、山区等
- 排查是否为设备天线问题
- 如果经常出现连接被动断开:
1) 检查下mqtt keep alive的时间,一般建议使用2分钟【如果每2分钟内都有应用数据收发,则可以把mqtt keep alive的时间设置的长一点儿】,除非有强制要求,否则不能太长,也不能太短。不建议超过4分钟,基站策略会关闭长时间没有数据传输的连接,太长时间可能会导致连接被基站关闭;不建议少于1分钟,太短时间可能会因为网络环境波动导致上行数据发送超时,可能超过1.5倍的心跳时间,从而被服务器主动断开连接
2) 检查下是否在1.5倍的mqtt keep alive的时间,没有成功发送数据到服务器,就会被被服务器主动断开,这种情况一般都是发送数据超时引起的
相关资料以及购买链接
Air724UG开发板
[Air724 开发板使用说明](https://doc.openluat.com/article/2236