mqtt - mqtt 客户端
作者:马梦阳
一、概述
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种基于发布/订阅模式的轻量级通信协议。你可以把它想象成一个邮局系统:
- 发布者(Publisher):就像寄信的人,把消息发送到特定的“邮箱”(主题)。
- 订阅者(Subscriber):就像收信的人,他们事先告诉邮局(Broker)他们对哪些“邮箱”(主题)的信件感兴趣。
- Broker(代理):就像邮局,负责接收发布者的消息,并根据订阅者的兴趣将消息分发给他们。
MQTT 协议由 IBM 在 1999 年开发,现在是 ISO 标准(ISO/IEC 20922),适用于物联网(IoT)和机器对机器(M2M)通信。
LuatOS 提供 mqtt 核心库,可以实现 mqtt 客户端,不过有几点需要大家知晓:
1. 只支持 mqtt 3.1.1,其他版本例如 3.1 或者 5.0 均不支持!!!
2. 只支持纯 MQTT/MQTTS 通信,不支持 mqtt over websocket;
3. 几个大前提:
- 本库基于 TCP 连接,支持加密 TCP 和非加密 TCP;
- 任何通信失败都将断开连接,如果开启了自动重连,那么间隔 N 秒后会开始自动重连;
- 上行数据均为一次性的,没有缓存机制,更没有上行的重试/重发机制;
4. 重要的事情说 3 次:没有重发机制,没有重发机制,没有重发机制
- MQTT 协议中规定了重发机制,但那是云端/服务器端才会实现的机制,模块端是没有的;
- 上行失败,唯一的可能性就是 TCP 链接出问题了,而 TCP 链接出问题的解决办法就是重连;
- 模块端不会保存任何上行数据,重连后也无法实现重发;
二、核心示例
1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/mqtt;
mqtt 客户端
--根据自己的服务器修改以下参数
local mqtt_host = "lbsmqtt.airm2m.com"
local mqtt_port = 1884
local mqtt_isssl = false
local client_id = "abc"
local user_name = "user"
local password = "password"
local pub_topic = "/luatos/pub/" .. (mcu.unique_id():toHex())
local sub_topic = "/luatos/sub/" .. (mcu.unique_id():toHex())
-- local topic2 = "/luatos/2"
-- local topic3 = "/luatos/3"
local mqttc = nil
sys.taskInit(function()
-- 等待联网
local ret, device_id = sys.waitUntil("IP_READY")
-- 下面的是mqtt的参数均可自行修改
client_id = device_id
pub_topic = "/luatos/pub/" .. device_id
sub_topic = "/luatos/sub/" .. device_id
-- 打印一下上报(pub)和下发(sub)的topic名称
-- 上报: 设备 ---> 服务器
-- 下发: 设备 <--- 服务器
-- 可使用mqtt.x等客户端进行调试
log.info("mqtt", "pub", pub_topic)
log.info("mqtt", "sub", sub_topic)
-- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
-- if crypto.cipher_suites then
-- log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
-- end
if mqtt == nil then
while 1 do
sys.wait(1000)
log.info("bsp", "本bsp未适配mqtt库, 请查证")
end
end
-------------------------------------
-------- MQTT 演示代码 --------------
-------------------------------------
mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl)
mqttc:auth(client_id,user_name,password) -- client_id必填,其余选填
-- mqttc:keepalive(240) -- 默认值240s
mqttc:autoreconn(true, 3000) -- 自动重连机制
mqttc:on(function(mqtt_client, event, data, payload)
-- 用户自定义代码
log.info("mqtt", "event", event, mqtt_client, data, payload)
if event == "conack" then
-- 联上了
sys.publish("mqtt_conack")
mqtt_client:subscribe(sub_topic)--单主题订阅
-- mqtt_client:subscribe({[topic1]=1,[topic2]=1,[topic3]=1})--多主题订阅
elseif event == "recv" then
log.info("mqtt", "downlink", "topic", data, "payload", payload)
sys.publish("mqtt_payload", data, payload)
elseif event == "sent" then
-- log.info("mqtt", "sent", "pkgid", data)
-- elseif event == "disconnect" then
-- 非自动重连时,按需重启mqttc
-- mqtt_client:connect()
end
end)
-- mqttc自动处理重连, 除非自行关闭
mqttc:connect()
sys.waitUntil("mqtt_conack")
while true do
-- 演示等待其他task发送过来的上报信息
local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 300000)
if ret then
-- 提供关闭本while循环的途径, 不需要可以注释掉
if topic == "close" then break end
mqttc:publish(topic, data, qos)
end
-- 如果没有其他task上报, 可以写个空等待
--sys.wait(60000000)
end
mqttc:close()
mqttc = nil
end)
mqtt ssl 客户端
--根据自己的服务器修改以下参数
local mqtt_host = "broker.emqx.io"
local mqtt_port = 8883
local mqtt_isssl = true -- 是否使用ssl> false 不加密 | true 无证书加密 | table 有证书加密
-- 带证书的ssl连接,把证书文件作为脚本文件一起烧录到模块内,就可以用/luadb/路径直接读取
mqtt_isssl = {
server_cert = io.readFile("/luadb/broker.emqx.io-ca.crt"),
client_cert=nil,
client_key=nil,
client_password=nil,
}
local client_id = "abc"
local user_name = "user"
local password = "password"
local pub_topic = "/luatos/pub/" .. (mcu.unique_id():toHex())
local sub_topic = "/luatos/sub/" .. (mcu.unique_id():toHex())
-- local topic2 = "/luatos/2"
-- local topic3 = "/luatos/3"
local mqttc = nil
sys.taskInit(function()
-- 等待联网
local ret, device_id = sys.waitUntil("IP_READY")
-- 下面的是mqtt的参数均可自行修改
client_id = device_id
pub_topic = "/luatos/pub/" .. device_id
sub_topic = "/luatos/sub/" .. device_id
-- 打印一下上报(pub)和下发(sub)的topic名称
-- 上报: 设备 ---> 服务器
-- 下发: 设备 <--- 服务器
-- 可使用mqtt.x等客户端进行调试
log.info("mqtt", "pub", pub_topic)
log.info("mqtt", "sub", sub_topic)
-- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
-- if crypto.cipher_suites then
-- log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
-- end
if mqtt == nil then
while 1 do
sys.wait(1000)
log.info("bsp", "本bsp未适配mqtt库, 请查证")
end
end
-------------------------------------
-------- MQTT 演示代码 --------------
-------------------------------------
mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl)
mqttc:auth(client_id,user_name,password) -- client_id必填,其余选填
-- mqttc:keepalive(240) -- 默认值240s
mqttc:autoreconn(true, 3000) -- 自动重连机制
mqttc:on(function(mqtt_client, event, data, payload)
-- 用户自定义代码
log.info("mqtt", "event", event, mqtt_client, data, payload)
if event == "conack" then
-- 联上了
sys.publish("mqtt_conack")
mqtt_client:subscribe(sub_topic)--单主题订阅
-- mqtt_client:subscribe({[topic1]=1,[topic2]=1,[topic3]=1})--多主题订阅
elseif event == "recv" then
log.info("mqtt", "downlink", "topic", data, "payload", payload)
sys.publish("mqtt_payload", data, payload)
elseif event == "sent" then
-- log.info("mqtt", "sent", "pkgid", data)
-- elseif event == "disconnect" then
-- 非自动重连时,按需重启mqttc
-- mqtt_client:connect()
end
end)
-- mqttc自动处理重连, 除非自行关闭
mqttc:connect()
sys.waitUntil("mqtt_conack")
while true do
-- 演示等待其他task发送过来的上报信息
local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 300000)
if ret then
-- 提供关闭本while循环的途径, 不需要可以注释掉
if topic == "close" then break end
mqttc:publish(topic, data, qos)
end
-- 如果没有其他task上报, 可以写个空等待
--sys.wait(60000000)
end
mqttc:close()
mqttc = nil
end)
三、常量详解
核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
mqtt.STATE_DISCONNECT
常量含义:mqtt断开,表示mqtt客户端当前处于断开连接的状态,没有与mqtt服务器建立任何连接;
数据类型:number;
取值范围:0;
示例代码:-- 如下方所示,为mqtt.STATE_DISCONNECT变量的最基本写法;
if mqtt.STATE_DISCONNECT == mqttc:state() then
-- 状态:MQTT断开连接
log.info("MQTT状态", "当前状态:断开连接")
end
mqtt.STATE_SCONNECT
常量含义:mqtt socket连接中,表示mqtt客户端正在尝试建立底层socket连接,但尚未完成连接过程;
数据类型:number;
取值范围:1;
示例代码:-- 如下方所示,为mqtt.STATE_SCONNECT变量的最基本写法;
if mqtt.STATE_SCONNECT == mqttc:state() then
-- 状态:MQTT Socket连接中
log.info("MQTT状态", "当前状态:Socket连接中")
end
mqtt.STATE_MQTT
常量含义:mqtt socket已连接,mqtt连接中,表示底层socket连接已成功建立,但mqtt协议层面的连接(如发送CONNECT消息、等待CONNACK响应)正在进行中;
数据类型:number;
取值范围:2;
示例代码:-- 如下方所示,为mqtt.STATE_MQTT变量的最基本写法;
if mqtt.STATE_MQTT == mqttc:state() then
-- 状态:Socket已连接,MQTT连接中
log.info("MQTT状态", "当前状态:MQTT协议连接中")
end
mqtt.STATE_READY
常量含义:mqtt mqtt已连接,表示mqtt客户端已成功完成所有连接步骤,处于完全就绪状态,可以进行发布消息、订阅主题等操作;
数据类型:number;
取值范围:3;
示例代码:-- 如下方所示,为mqtt.STATE_READY变量的最基本写法;
if mqtt.STATE_READY == mqttc:state() then
-- 状态:MQTT已完全连接就绪
log.info("MQTT状态", "当前状态:已连接就绪")
end
四、函数详解
mqttc:debug(onoff)
功能
配置是否打开 debug 信息,即控制 mqtt 客户端是否输出调试信息;
注意事项
1. 必须传入布尔类型参数 onoff(true 表示打开调试,false 表示关闭调试);
2. 建议开发调试阶段可打开,方便查看 mqtt 通信的详细过程。调试结束后应关闭,以减少不必要的日志输出;
参数
onoff
参数含义:是否打开debug信息,true表示打开调试,false表示关闭调试;
数据类型:boolean;
取值范围:true/false;
是否必选:必须传入此参数;
注意事项:必须是布尔类型(true/false);
参数示例:-- 如下方所示,传入值为true,表示打开调试;
mqttc:debug(true)
-- 如下方所示,传入值为true,表示关闭调试;
mqttc:debug(false)
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,传入值为true,表示打开调试;
mqttc:debug(true)
-- 如下方所示,传入值为true,表示关闭调试;
mqttc:debug(false)
mqtt.create(adapter, host, port, ssl, isipv6)
功能
mqtt 客户端创建;
注意事项
1. 返回值有返回 nil 的情况,在调用后必须进行检查返回值是否为 nil,且要做逻辑处理;
参数
adapter
参数含义:适配器序号,如果不填,会选择平台自带的方式,然后是最后一个注册的适配器,可选值请查阅socket库的常量表;
数据类型:number或者nil;
取值范围:number类型时,取值范围参考socket api中的常量详解;
是否必选:可选传入此参数;
注意事项:如果没有传入此参数,内核固件会自动选择当前时间点其他功能模块设置的默认网卡;
除非你mqtt请求时,一定要使用某一种网卡,才设置此参数;
如果没什么特别要求,不要设置此参数,使用系统中设置的默认网卡即可;
一般来说,LuatOS的网络应用demo中都会有netdrv_device功能模块设置默认网卡;
所以建议使用mqtt.create接口时,不要设置此参数,直接使用netdrv_device设置的默认网卡就行;
参数示例:-- 如下方所示,这是普通TCP连接的写法,第一个参数不填时默认为平台自带方式或最后注册的适配器;
mqttc = mqtt.create(nil,"120.55.137.106", 1884)
-- 如下方所示,这是普通TCP连接的写法,查阅socket库的常量表,将需要的常量填到第一个参数的位置;
mqttc = mqtt.create(socket.LWIP_GP,"120.55.137.106", 1884)
host
参数含义:服务器地址,可以是域名,也可以是ip地址;
数据类型:string;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:支持字符串形式的域名或IP地址;
代码中有TODO注释提示host长度超过191可能有问题,实际使用中应避免过长的host;
作为必需参数,若不提供会导致错误;
参数示例:-- 如下方所示,这是普通TCP连接的写法,第二个参数支持域名或者ip地址;
mqttc = mqtt.create(nil,"120.55.137.106", 1884)
-- 如下方所示,这是普通TCP连接的写法,第二个参数支持域名或者ip地址;
mqttc = mqtt.create(nil,"lbsmqtt.airm2m.com", 1884)
port
参数含义:端口号;
数据类型:number;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:作为必需参数,若不提供会导致错误;
参数示例:-- 如下方所示,这是普通TCP连接的写法,第三个参数必须填有效的整数值;
mqttc = mqtt.create(nil,"120.55.137.106", 1884)
-- 如下方所示,这是普通TCP连接的写法,第三个参数必须填有效的整数值;
mqttc = mqtt.create(nil,"lbsmqtt.airm2m.com", 1884)
ssl
参数含义:ssl加密配置;默认为不加密;
true时为无证书最简单的加密;
table时为有证书的加密,table内容格式说明如下
{
-- 参数含义:服务器ca证书数据;
-- 数据类型:string/nil;
-- 取值范围:无特别限制;
-- 是否必选:可选传入此参数;
-- 注意事项:当客户端需要验证服务器证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给server_cert;
-- 参数示例:例如通过Luatools烧录了server_ca.crt文件,就可以通过io.readFile("/luadb/server_ca.crt")读出文件内容赋值给赋值给server_cert;
server_cert
-- 参数含义:客户端证书数据;
-- 数据类型:string/nil;
-- 取值范围:无特别限制;
-- 是否必选:可选传入此参数;
-- 注意事项:当服务器需要验证客户端证书时,需要此参数,如果证书数据在一个文件中,要把文件内容读出来,赋值给client_cert;
-- 参数示例:例如通过Luatools烧录了client.crt文件,就可以通过io.readFile("/luadb/client.crt")读出文件内容赋值给赋值给client_cert;
client_cert
-- 参数含义:加密后的客户端私钥数据;
-- 数据类型:string/nil;
-- 取值范围:无特别限制;
-- 是否必选:可选传入此参数;
-- 注意事项:当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_key;
-- 参数示例:例如通过Luatools烧录了client.key文件,就可以通过io.readFile("/luadb/client.key")读出文件内容赋值给client.key;
client_key
-- 参数含义:客户端私钥口令数据;
-- 数据类型:string/nil;
-- 取值范围:无特别限制;
-- 是否必选:可选传入此参数;
-- 注意事项:当服务器需要验证客户端证书时,需要此参数,如果加密后的私钥数据在一个文件中,要把文件内容读出来,赋值给client_password;
-- 参数示例:例如通过Luatools烧录了clinet.password文件,就可以通过io.readFile("/luadb/clinet.password")读出文件内容赋值给client_password;
client_password
-- 参数含义:控制是否验证服务器证书的有效性;
-- 数据类型:number;
-- 取值范围:0 不校验服务器证书;
-- 1 可选校验;
-- 2 强制校验;
-- 是否必选:可选传入此参数,不填时,默认为2;
-- 注意事项:测试环境或者自签名证书场景下可根据需要降低校验级别;
-- 正式环境建议使用强制校验以提高安全性;
-- 参数示例:verify = 1;
verify
}
数据类型:boolean/table;
取值范围:无特别限制;
是否必选:可选传入此参数,不填时默认为不使用加密连接;
注意事项:非必选参数,不填时默认为不使用加密连接;
证书数据需为字符串格式,通常通过io.readFile接口从文件读取;
当使用表类型参数时,即使只设置了一个证书相关字段,也会启用完整的TLS连接模式;
verify参数会影响连接安全性,正式环境建议使用默认值2(强制校验);
参数示例:-- 如下方所示,这是普通TCP连接的写法,第四个参数不填时默认为不使用加密连接;
mqttc = mqtt.create(nil,"120.55.137.106", 1884)
-- 如下方所示,这是加密TCP连接的写法,第四个参数填true为无证书最简单的加密,不验证服务器证书,即我们常说的无证书校验;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, true)
-- 如下方所示,这是加密TCP连接的写法,第四个参数现在是表类型,并且只填了一个server_cert参数,为单服务器证书验证,即我们常说的单向认证;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, {server_cert=io.readFile("/luadb/server_ca.crt")})
-- 如下方所示,这是加密TCP连接的写法,第四个参数现在是表类型,并且填了server_cert参数和verify参数,同时verify参数的值为1,为单服务器证书验证+可选认证;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, {server_cert=io.readFile("/luadb/server_ca.crt"), verify=1})
-- 如下方所示,这是加密TCP连接的写法,第四个参数现在是表类型,并且填了server_cert、client_cert、client_key、client_password参数,为双向证书验证,即我们常说的双向认证;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, {
server_cert=io.readFile("/luadb/server_ca.crt"),
client_cert=io.readFile("/luadb/client.crt"),
client_key=io.readFile("/luadb/client.key"),
client_password="123456",
})
isipv6
参数含义:是否使用ipv6协议以及设置接收缓冲区大小;
默认为ipv4协议;
布尔类型时,true表示使用ipv6协议,false表示使用ipv4协议;
表类型时,可同时配置多个扩展参数,表内容规范如下
{
-- 参数含义:设置是否使用ipv6协议;
-- 数据类型:boolean;
-- 取值范围:true/false;
-- 是否必选:可选传入此参数;
-- 注意事项:ipv6功能需要设备和网络环境支持,否则即使设置为true也无法连接;
-- 参数示例:ipv6 = true;
ipv6
-- 参数含义:设置mqtt接收缓冲区的大小(单位:字节);
-- 数据类型:number;
-- 取值范围:大于0的整数;
-- 是否必选:可选传入此参数;
-- 注意事项:增大缓冲区可以提高接收大数据包的能力,但会占用更多内存;
-- 减小缓冲区可以节省内存,但可能导致大数据包接收不完整;
-- 应根据实际应用场景和设备内存资源合理设置;
-- 参数示例:rxSize = 4096;
rxSize
}
数据类型:boolean/table;
取值范围:无特别限制;
是否必选:可选传入此参数,不填时默认为ipv4协议;
注意事项:不填或为nil时,默认使用IPv4协议;
接收缓冲区大小默认为内部设定值,不通过rxSize参数自定义;
ipv6功能需要设备和网络环境支持,否则即使设置为true也无法连接;
在网络不稳定环境下,适当增大rxSize可以提高消息接收的稳定性;
参数示例:-- 如下方所示,这是普通TCP连接的写法,第五个参数不填时为使用ipv4协议;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, nil)
-- 如下方所示,这是普通TCP连接的写法,第五个参数填true时为使用ipv6协议;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, nil, true)
-- 如下方所示,这是普通TCP连接的写法,第五个参数现在是表类型,并且填了rxSize参数,为自定义设置mqtt接收缓冲区大小为4096字节,不过还是使用ipv4协议;
mqttc = mqtt.create(nil,"120.55.137.106", 1884, nil, {rxSize = 4096})
-- 如下方所示,这是普通TCP连接的写法,第五个参数现在是表类型,并且填了ipv6参数和rxSize参数,为自定义设置mqtt接收缓冲区大小为4096字节,且使用ipv6协议;
mqttc = mqtt.create(nil,"120.55.137.106", 1884, nil, {ipv6 = true, rxSize = 4096})
返回值
local mqttc = mqtt.create(adapter, host, port, ssl, isipv6)
有一个返回值 mqttc
mqttc
含义说明:判断mqtt客户端创建是否成功,成功时返回一个userdata类型的MQTT客户端实例,该实例可用于后续的MQTT操作(如连接、订阅、发布等),失败时返回nil;
数值类型:userdata/nil;
取值范围:无特别限制;
注意事项:有返回nil的情况,需做好对应逻辑处理;
示例
-- 如下方所示,这是普通TCP连接的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 1884)
-- 如下方所示,这是普通TCP连接、使用ipv6协议的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, nil, true)
-- 如下方所示,这是普通TCP连接、mqtt接收缓冲区自定义4096字节的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 1884, nil, {rxSize = 4096})
-- 如下方所示,这是加密TCP连接、不验证服务器证书的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, true)
-- 如下方所示,这是加密TCP连接、单服务器证书验证的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, {server_cert=io.readFile("/luadb/server_ca.crt")})
-- 如下方所示,这是加密TCP连接、单服务器证书验证、可选认证的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, {server_cert=io.readFile("/luadb/server_ca.crt"), verify=1})
-- 如下方所示,这是加密TCP连接、双向证书验证的写法;
mqttc = mqtt.create(nil,"120.55.137.106", 8883, {
server_cert=io.readFile("server_ca.crt"),
client_cert=io.readFile("/luadb/client.crt"),
client_key=io.readFile("/luadb/client.key"),
client_password="123456",
})
mqttc:auth(client_id,username,password,cleanSession)
功能
配置 mqtt 三元组信息及会话清除策略(cleanSession);
注意事项
1. client_id、username、password 有长度限制,其中 client_id 和 username 限制不超过 192 字符,password 限制不超过 512 字符,超过限制会导致配置失败;
2. 相同的 client_id 在同一服务器上会导致设备互相踢下线,需要确保 client_id 的唯一性;
参数
client_id
参数含义:设备识别id,对于同一个mqtt服务器来说,通常要求唯一,相同client_id会互相踢下线;
数据类型:string;
取值范围:最大长度为192个字符;
是否必选:可选传入此参数,不填的时候为随机生成的ID;
注意事项:对于同一个MQTT服务器,client_id通常要求是唯一的;
如果多个客户端使用相同的client_id连接同一服务器,会导致设备互相踢下线;
client_id最大长度为192字符。超过此长度会导致认证失败,接口返回nil并输出错误日志;
参数示例:-- 如下方所示,这是无账号密码登录的写法,第一个参数的“123456789”为建立mqtt客户端时的client_id;
mqttc:auth("123456789")
-- 如下方所示,这是不填client_id时的写法,此时会进入无clientID模式,服务器随机生成client_id;
mqttc:auth()
username
参数含义:连接mqtt服务器时使用的用户名信息;
数据类型:string;
取值范围:0-192字符;
是否必选:可选传入此参数,如不填,默认为空字符串;
注意事项:若提供的用户名长度超过限制,会导致接口调用失败(返回nil),并在日志中打印错误信息"mqtt username 太长或者无效!!!!";
该参数仅用于mqtt服务器的身份验证,具体验证逻辑由服务器决定;
即使不提供账号密码(使用默认空字符串),也可以调用该接口进行身份配置;
参数示例:-- 如下方所示,这是不填用户名的写法,不填默认为空字符串;
mqttc:auth("123456789")
-- 如下方所示,这是填写用户名的写法,“username”为用户名,“password”为密码;
mqttc:auth("123456789","username","password")
password
参数含义:连接mqtt服务器时使用的密码信息,用于身份验证;
数据类型:string;
取值范围:0-192字符;
是否必选:可选传入此参数,如不填,默认为空字符串;
注意事项:若提供的密码长度超过限制,会导致接口调用失败(返回nil),并在日志中打印错误信息"mqtt password 太长或者无效!!!!";
该参数与username配合使用,用于mqtt服务器的身份验证,具体验证逻辑由服务器决定;
即使不提供密码(使用默认空字符串),也可以调用该接口进行身份配置;
参数示例:-- 如下方所示,这是不填用户名密码的写法,不填默认为空字符串;
mqttc:auth("123456789")
-- 如下方所示,这是填写用户名的写法,“username”为用户名,“password”为密码;
mqttc:auth("123456789","username","password")
cleanSession
参数含义:控制是否清除mqtt会话状态;
当设置为true时,客户端连接服务器时会清除之前的会话状态(包括未完成的订阅、消息队列等);
当设置为false时,服务器会保留客户端的会话状态,以便客户端重连后恢复之前的订阅和未接收的消息;
数据类型:boolean;
取值范围:true/false;
是否必选:可选传入此参数,如不填,默认为true;
注意事项:仅当提供了client_id参数时,cleanSession参数的配置才有效;
在无clientId模式下(即调用mqttc:auth()不带参数,由服务器随机生成clientId),cleanSession不可配置;
该参数的设置会直接影响客户端重连后的行为:设置为false时,重连后服务器会推送客户端离线期间未接收的QoS 1和QoS 2消息;设置为true时,重连后不会恢复之前的会话状态;
若服务器不支持会话保留功能,即使设置为true,也可能无法保留会话状态;
参数示例:-- 如下方所示,不手动设置cleanSession参数时默认为true;
mqttc:auth("123456789")
-- 如下方所示,手动设置cleanSession参数为false,不清除mqtt会话状态;
mqttc:auth("123456789","username","password", false)
-- 如下方所示,无clientId模式,服务器随机生成id,cleanSession不可配置;
mqttc:auth()
返回值
local mqtt_auth_result = mqttc:auth(client_id,username,password,cleanSession)
有一个返回值 mqtt_auth_result
mqtt_auth_result
含义说明:连接mqtt服务器时身份验证配置是否成功
数值类型:boolean;
取值范围:成功时返回true,失败时返回nil;
注意事项:返回值是2025年3月19日新增的特性;
实际使用中,应检查返回值以确认身份验证配置是否成功;
示例
-- 如下方所示,这是无clientId模式的写法,服务器随机生成id,cleanSession不可配置;
mqttc:auth()
-- 如下方所示,这是仅clientID的写法,无用户名密码登录;
mqttc:auth("123456789")
-- 如下方所示,这是带用户名密码登录;
mqttc:auth("123456789","username","password")
-- 如下方所示,这是手动配置cleanSession参数为false的写法,不清除mqtt会话状态;
mqttc:auth("123456789","username","password", false)
mqttc:keepalive(time)
功能
设置 mqtt 客户端的心跳时间间隔,单位为秒(s);
注意事项
1. 参数 time 为可选值,默认值为 240 秒,最小值限制为 15 秒(若传入小于 15 的值,会被强制设为 15 秒),最大值限制为 600 秒(若传入大于 600 的值,会被强制设为 600 秒);
2. 建议在 mqtt 连接前设置心跳参数,也可以在连接后动态调整心跳时间;
3. 网络不稳定环境可适当减小心跳间隔(如 30-60 秒),但不要低于 15 秒;
4. 网络稳定环境可使用默认值 240 秒,或根据服务器要求调整;
5. 心跳间隔过短会增加功耗和网络流量,过长可能导致连接被服务器过早断开;
参数
time
参数含义:用于设置mqtt客户端的心跳时间间隔,即客户端向服务器发送心跳包的时间间隔;
数据类型:number;
取值范围:最小值:15秒(若传入小于15的值,会被强制设为15秒);
最大值:600秒(若传入大于600的值,会被强制设为600秒);
是否必选:可选传入此参数,若不传入,默认值为240秒;
注意事项:单位为秒(s),无需额外转换单位;
传入值会被自动截断到有效范围内(15-600秒);
心跳间隔过短会增加设备功耗和网络流量,过长可能导致连接被服务器过早判定为断开;
建议根据网络稳定性调整:网络不稳定时可设为30-60秒,网络稳定时使用默认值240秒或根据服务器要求设置;
该参数可在连接前或连接后设置,连接后设置会覆盖之前的值;
参数示例:-- 如下方所示,这是使用默认值240秒的写法;
mqttc:keepalive()
-- 如下方所示,这是设置为30秒的写法;
mqttc:keepalive(30)
-- 如下方所示,传入超出范围的值会被截断;
mqttc:keepalive(10) -- 实际生效为15秒;
mqttc:keepalive(800) -- 实际生效为600秒;
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,这是使用默认值240秒的写法;
mqttc:keepalive()
-- 如下方所示,这是设置为30秒的写法;
mqttc:keepalive(30)
-- 如下方所示,传入超出范围的值会被截断;
mqttc:keepalive(10) -- 实际生效为15秒;
mqttc:keepalive(800) -- 实际生效为600秒;
mqttc:will(topic, payload, qos, retain)
功能
设置 mqtt 客户端的遗嘱消息;
注意事项
1. 必须在调用 mqttc:connect() 之前调用此接口,否则遗嘱消息设置不会生效;
参数
topic
参数含义:遗嘱消息的主题;
数据类型:string;
取值范围:根据MQTT 3.1.1标准协议,最小长度为1字节,最大长度为65535字节。LuatOS对此不做限制;
是否必选:必须传入此参数;
注意事项:必须在调用mqttc:connect()之前设置,否则无效;
主题中的特殊字符需要按照MQTT协议规范进行处理;
建议为每个设备或场景设计唯一的遗嘱主题,以便于接收端识别;
topic和payload共同构成完整的遗嘱消息,应合理设计两者内容;
参数示例:-- 如下方所示,需要在调用mqttc:connect()之前设置,否则无效;
mqttc:will("/luatos/123456", "123")
mqttc:connect()
payload
参数含义:mqtt客户端设置的遗嘱消息内容;
数据类型:string;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:必须在调用mqttc:connect()之前设置,否则无效;
如果包含非ASCII字符,需要确保编码格式与接收端一致;
topic和payload共同构成完整的遗嘱消息,应合理设计两者内容;
参数示例:-- 如下方所示,需要在调用mqttc:connect()之前设置,否则无效;
mqttc:will("/luatos/123456", "123")
mqttc:connect()
qos
参数含义:mqtt客户端设置的遗嘱消息的服务质量等级;
数据类型:number;
取值范围:根据MQTT 3.1.1标准协议规范,有效值为
qos 0(最多一次):消息可能丢失,也可能因为网络层或中间件的意外重放而出现重复,但MQTT协议本身不 会主动再发一次;
qos 1(至少一次):发送端会一直重试,直到收到接收端的PUBACK确认,因此消息至少送达一次,但也可能因确认丢失而被重复投递;
qos 2(只有一次):通过四步握手(PUBLISH → PUBREC → PUBREL → PUBCOMP)保证消息恰好送达一次;若任一步丢失,发送端会重传对应报文,直至整个流程完成,从而避免重复或丢失;
是否必选:可选传入此参数,如不填,默认为0;
注意事项:必须在调用mqttc:connect()之前设置,否则无效;
如果不指定,默认使用qos 0;
确保mqtt服务器支持所设置的qos级别;
参数示例:-- 如下方所示,使用默认qos 0(最多一次);
mqttc:will("/luatos/123456", "123")
-- 如下方所示,设置qos 1(至少一次);
mqttc:will("/luatos/123456", "123", 1)
-- 如下方所示,设置qos 2(恰好一次);
mqttc:will("/luatos/123456", "123", 2)
-- 注意:必须在connect前设置;
mqttc:connect()
retain
参数含义:控制遗嘱消息的保留性;
数据类型:number;
取值范围:0/1;
是否必选:可选传入此参数,不填时,默认为0;
注意事项:必须在调用mqttc:connect()之前设置,连接后设置无效;
当retain=1时,服务器会保留该遗嘱消息,并在有新客户端订阅相应主题时立即发送此消息;
如果同一主题有新的保留消息发布,旧的保留消息将被替换;
参数示例:-- 如下方所示,使用默认retain参数,默认为0;
mqttc:will("/luatos/123456", "123")
-- 如下方所示,设置retain参数为1,保留遗嘱消息;
mqttc:will("/luatos/123456", "123", , 1)
-- 如下方所示,同时设置qos参数为1,retain参数为1;
mqttc:will("device/status", "offline", 1, 1)
-- 注意:必须在connect前设置;
mqttc:connect()
返回值
local mqtt_will_result = mqttc:will(topic, payload, qos, retain)
有一个返回值 mqtt_will_result
mqtt_will_result
含义说明:判断设置遗嘱消息操作是否成功;
数值类型:boolean;
取值范围:true/false;
注意事项:返回值仅表示设置操作是否成功,不保证遗嘱消息最终会被服务器发布,遗嘱消息只有在客户端意外断开连接时才会由服务器发布;
必须在调用mqttc:connect()之前设置遗嘱消息,连接后设置将返回false;
示例
-- 如下方所示,设置遗嘱消息并检查是否成功;
local mqtt_will_result = mqttc:will("/luatos/123456", "123", 1, 1)
if mqtt_will_result then
log.info("遗嘱消息设置成功")
-- 继续执行连接操作;
mqttc:connect()
else
log.info("遗嘱消息设置失败,请检查参数或客户端状态")
-- 进行错误处理;
end
mqttc:autoreconn(reconnect, reconnect_time)
功能
用于配置 mqtt 客户端的自动重连功能,包括启用/禁用自动重连以及设置重连周期;
注意事项
1. 该接口仅控制自动重连的配置,不直接执行重连操作;
2. 重连功能仅在连接断开后生效,不会主动尝试断开现有连接;
3. 如果项目中使用多网卡功能,一定不要使用此接口,否则内核固件在自动重连时,可能会使用错误的网卡,导致无法上网;
参数
reconnect
参数含义:控制是否启用mqtt客户端的自动重连功能;
数据类型:boolean;
取值范围:true/false;
是否必选:可选传入此参数;
注意事项:若启用自动重连(设置为true),需注意重连周期(reconnect_time参数)会受到限制,若配置的重连周期小于1000ms,系统会强制将其调整为1000ms,以避免过于频繁的重连尝试;
该参数仅控制自动重连的开关状态,不直接执行重连操作,实际重连行为发生在连接断开后;
建议在调用mqttc:connect()前配置该参数,以确保连接建立前重连策略已正确设置;
参数示例:-- 如下方所示,启用mqtt客户端的自动重连功能;
mqttc:autoreconn(true)
-- 如下方所示,禁用mqtt客户端的自动重连功能;
mqttc:autoreconn(false)
reconnect_time
参数含义:设置mqtt客户端自动重连的时间间隔;
数据类型:number;
取值范围:≥1000ms的整数(若设置值小于1000ms,系统会强制将其调整为1000ms),默认值为3000ms;
是否必选:可选传入此参数,若不填默认为3000ms;
注意事项:参数单位为毫秒(ms),配置时需注意时间单位转换;
当自动重连功能启用时,系统会确保重连周期不小于1000ms,以避免过于频繁的重连请求对服务器造成压力;
该参数只有在自动重连功能启用(reconnect为true)时才有实际作用;
可以单独配置该参数而不改变自动重连开关状态(例如仅调整重连周期,不改变是否自动重连);
参数示例:-- 如下方所示,启用自动重连功能,默认重连周期为3000ms;
mqttc:autoreconn(true)
-- 如下方所示,启用自动重连功能,设置重连周期为5000ms;
mqttc:autoreconn(true, 5000)
-- 如下方所示,启用自动重连功能,设置重连周期小于1000ms的周期(实际会被调整为1000ms);
mqttc:autoreconn(true, 500) -- 实际重连周期为1000ms
-- 如下方所示,不改变自动重连功能的状态,仅调整重连周期为4000ms;
mqttc:autoreconn(nil, 4000)
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,启用自动重连功能,默认重连周期为3000ms;
mqttc:autoreconn(true)
-- 如下方所示,启用自动重连功能,设置重连周期为5000ms;
mqttc:autoreconn(true, 5000)
-- 如下方所示,启用自动重连功能,设置重连周期小于1000ms的周期(实际会被调整为1000ms);
mqttc:autoreconn(true, 500) -- 实际重连周期为1000ms
-- 如下方所示,不改变自动重连功能的状态,仅调整重连周期为4000ms;
mqttc:autoreconn(nil, 4000)
mqttc:on(cb)
功能
注册 mqtt 客户端的事件回调函数;
注意事项
1. 回调函数应保持简洁高效 ,避免执行耗时操作(如复杂计算、阻塞 IO 等),否则可能影响 mqtt 客户端的消息处理实时性;
参数
cb
参数含义:mqtt事件回调函数;
该回调函数接收以下五个参数,在不同事件类型下参数含义有所不同;
数据类型:function;
取值范围:回调函数本身无取值范围这一说法;
是否必选:必须传入此参数;
注意事项:每次调试会覆盖之前注册的回调函数;
-- 参数含义:mqtt客户端对象本身;
-- 数据类型:string;
-- 取值范围:无限制;
-- 是否必选:必须传入此参数;
-- 注意事项:所有事件类型都会传递此参数,可用于在回调中操作客户端(如重连、发布消息等);
mqtt_client
-- 参数含义:事件类型标识符;
-- 数据类型:string;
-- 取值范围:
conack -- 服务器鉴权完成,表示mqtt连接已建立,可以订阅和发布数据;
suback -- 订阅完成;
unsuback -- 取消订阅完成;
recv -- 接收到服务器下发的数据;
sent -- 数据发送完成;
disconnect -- 服务器断开连接;
pong -- 收到服务器心跳应答;
error -- 发生严重异常,会导致断开连接;
-- 是否必选:必须传入此参数;
-- 注意事项:用于标识当前触发的mqtt事件类型,是回调函数中判断事件类型的核心依据;
event
-- 参数含义:事件相关的数据;
-- 数据类型:根据event类型不同而变化;
-- 取值范围:根据event类型不同而变化;
conack -- 无实际数据;
suback -- 布尔值(true表示成功,false表示失败);
unsuback -- 无实际数据;
recv -- 字符串(表示收到消息的topic);
sent -- 数值(表示消息ID);
disconnect -- 无实际数据;
pong -- 无实际数据;
error -- 字符串,取值范围为以下四种:
connect -- 服务器连接不上;
tx -- 发送数据失败;
conack -- 服务器鉴权失败;
other -- 其他异常;
-- 是否必选:可选传入此参数;
-- 注意事项:不同事件类型下数据类型和含义不同,需根据事件类型进行相应处理;
data
-- 参数含义:业务数据或结果码;
-- 数据类型:根据event类型不同而变化;
-- 取值范围:根据event类型不同而变化;
conack -- 无实际数据;
suback -- 成功时为0-2的整数(表示qos等级),失败时为失败码(一般是0x80);
unsuback -- 无实际数据;
recv -- 字符串(表示收到的业务数据内容);
sent -- 无实际数据;
disconnect -- 无实际数据;
pong -- 无实际数据;
error -- 仅在conack类型错误时为整数失败码,其他错误类型时无实际数据;
-- 是否必选:可选传入此参数;
-- 注意事项:通常与data参数配合使用,提供更详细的事件信息;
payload
-- 参数含义:消息元数据(仅在特定事件中存在)
-- 数据类型:table;
-- 取值范围:仅在recv事件中提供;
message_id -- 消息id;
qos -- 服务器质量等级,取值范围0、1、2;
retain -- 保留标志,取值范围0、1;
dup -- 重复标志,取值范围0、1;
-- 是否必选:可选传入此参数;
-- 注意事项:仅部分事件类型提供,主要用于获取消息的元数据信息,一般情况下可根据需要选择性处理;
metas
参数示例:-- 如下方所示,这是注册mqtt客户端的事件回调函数写法;
mqttc:on(function(mqtt_client, event, data, payload, metas)
-- 用户自定义代码
log.info("mqtt", "event", event, mqtt_client, data, payload)
end)
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- mqtt client的事件回调函数
local function mqtt_client_event_cbfunc(mqtt_client, event, data, payload, metas)
log.info("mqtt_client_event_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-- mqtt连接成功
if event == "conack" then
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", true)
-- 订阅单主题
-- 第二个参数表示qos,取值范围为0,1,2,如果不设置,默认为0
if not mqtt_client:subscribe(TOPIC_PREFIX .. "/down") then
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
end
-- 订阅多主题,如果有需要,打开注释
-- 表中的每一个订阅主题的格式为[topic]=qos
-- if not mqtt_client:subscribe(
-- {
-- [(TOPIC_PREFIX .. "/data"]=0,
-- [(TOPIC_PREFIX .. "/cmd"]=1
-- }
-- ) then
-- sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", false, -1)
-- end
-- 订阅结果
-- data:订阅应答结果,true为成功,false为失败
-- payload:number类型;成功时表示qos,取值范围为0,1,2;失败时表示失败码,一般是0x80
elseif event == "suback" then
-- 发送消息通知 mqtt main task
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "SUBSCRIBE", data, payload)
-- 取消订阅成功
elseif event == "unsuback" then
-- 发送消息通知 mqtt main task
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "UNSUBSCRIBE", true)
-- 接收到服务器下发的publish数据
-- data:string类型,表示topic
-- payload:string类型,表示payload
-- metas:table类型,数据内容如下
-- {
-- qos: number类型,取值范围0,1,2
-- retain:number类型,取值范围0,1
-- dup:number类型,取值范围0,1
-- message_id: number类型
-- }
elseif event == "recv" then
-- 对接收到的publish数据处理
mqtt_receiver.proc(data, payload, metas)
-- 发送成功publish数据
-- data:number类型,表示message id
elseif event == "sent" then
-- 发送消息通知 mqtt sender task
sys.sendMsg(mqtt_sender.TASK_NAME, "MQTT_EVENT", "PUBLISH_OK", data)
-- 服务器断开mqtt连接
elseif event == "disconnect" then
-- 发送消息通知 mqtt main task
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "DISCONNECTED", false)
-- 收到服务器的心跳应答
elseif event == "pong" then
-- 接收到数据,通知网络环境检测看门狗功能模块进行喂狗
sys.publish("FEED_NETWORK_WATCHDOG")
-- 严重异常,本地会主动断开连接
-- data:string类型,表示具体的异常,有以下几种:
-- "connect":tcp连接失败
-- "tx":数据发送失败
-- "conack":mqtt connect后,服务器应答CONNACK鉴权失败,失败码为payload(number类型)
-- "other":其他异常
elseif event == "error" then
if data == "connect" or data == "conack" then
-- 发送消息通知 mqtt main task,连接失败
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "CONNECT", false)
elseif data == "other" or data == "tx" then
-- 发送消息通知 mqtt main task,出现异常
sys.sendMsg(TASK_NAME, "MQTT_EVENT", "ERROR")
end
end
end
-- 注册mqtt client对象的事件回调函数
mqtt_client:on(mqtt_client_event_cbfunc)
mqttc:connect()
功能
连接 mqtt 服务器;
注意事项
1. 该接口返回 true 仅表示连接请求成功发起,不代表与 mqtt 服务器的连接已成功建立;
2. 该接口返回 false 仅表示连接请求失败,通常意味着底层 socket 创建或连接失败;
3. 调用该接口前必须先配置服务器地址、端口、客户端 ID 等参数,如果未配置必要参数,该接口可能返回 false;
参数
无;
返回值
local mqtt_connect_result = mqttc:connect()
有一个返回值 mqtt_connect_result
mqtt_connect_result
含义说明:表示mqtt连接请求是否成功发起;
数值类型:boolean;
取值范围:true/false;
注意事项:必须先通过mqttc:auth接口配置连接参数,否则连接请求可能失败;
返回值不代表实际连接成功,该接口仅表示连接请求是否成功发送,不代表已与mqtt服务器建立实际连接;
需通过mqttc:ready接口或注册的conack事件回调来确认连接是否真正建立;
示例
-- 开始建立连接
mqttc:connect()
-- 本函数仅代表发起成功, 后续仍需根据mqttc:ready接口判断mqtt是否连接正常
mqttc:ready()
功能
检查 mqtt 客户端是否处于就绪状态(已成功连接到 mqtt 服务器);
注意事项
1. 该接口仅检查客户端的内部状态标记,不进行实际的网络连通性测试;
2. 返回 true 仅表示客户端当前认为自己处于连接状态,不保证网络连接一定稳定;
3. 即使返回 true,后续的发布/订阅操作仍有可能因网络问题失败,建议做好错误处理;
参数
无;
返回值
local mqtt_ready_result = mqttc:ready()
有一个返回值 mqtt_ready_result
mqtt_ready_result
含义说明:判断客户端是否已经连接就绪;
数值类型:boolean;
取值范围:true/false;
注意事项:接口返回值仅检查客户端的内部状态标记,不进行实际的网络连通性测试;
返回true仅表示客户端当前认为自己处于连接状态,不保证网络连接一定稳定;
即使返回true,后续的发布/订阅操作仍有可能因网络问题失败,建议做好错误处理;
示例
-- 如下方所示,为一个最基本的mqttc:ready()接口的写法;
local mqtt_ready_result = mqttc:ready()
if mqtt_ready_result then
log.info("mqtt 客户端已就绪")
-- 用户处理代码
else
log.info("mqtt 客户端未就绪,正在尝试重连...")
-- 执行重连操作
end
mqttc:subscribe(topic, qos)
功能
订阅一个/多个主题(Topic);
注意事项
1. 需要先建立 mqtt 客户端且连接成功后再调用;
2. 订阅时 topic 的命名要合法,qos 的值要在规定范围内;
3. 多主题订阅下,只要有任一主题订阅失败,整体返回 nil,需注意订阅失败的处理逻辑;
参数
topic
参数含义:订阅主题时的主题名称;
数据类型:string/table;
取值范围:根据MQTT 3.1.1标准协议,最小长度为1字节,最大长度为65535字节。LuatOS对此不做限制;
是否必选:必须传入此参数;
注意事项:MQTT Topic的命名要符合规范;
示例代码:-- 如下方所示,这是订阅单个Topic的写法,“/luatos/123456” 为订阅的Topic名,其余参数请看后面解释;
mqttc:subscribe("/luatos/123456", 0)
-- 如下方所示,这是订阅多个Topic的写法,“/luatos/1234567” 和 “/luatos/12345678” 为订阅的两个不同Topic名,其余参数请看后面解释;
mqttc:subscribe({["/luatos/1234567"]=1,["/luatos/12345678"]=2})
qos
参数含义:服务质量等级,决定了一条消息最多被送达一次、至少被送达一次,还是恰好被送达一次;
QoS 0(最多一次):消息可能丢失,也可能因为网络层或中间件的意外重放而出现重复,但MQTT协议本身不 会主动再发一次;
QoS 1(至少一次):发送端会一直重试,直到收到接收端的PUBACK确认,因此消息至少送达一次,但也可能因确认丢失而被重复投递;
QoS 2(只有一次):通过四步握手(PUBLISH → PUBREC → PUBREL → PUBCOMP)保证消息恰好送达一次;若任一步丢失,发送端会重传对应报文,直至整个流程完成,从而避免重复或丢失。
数值类型:number;
取值范围:0/1/2;
是否必选:可选传入此参数,不填时默认为0;
注意事项:当订阅与发布的QoS不一致时,订阅者最终拿到的QoS=min(发布QoS, 订阅QoS);
Topic本身最大64k字节,但高QoS下Broker会把Topic+Payload一起缓存,过长Topic会放大内存占用,建议 Topic控制在100字节以内,尤其在高并发高QoS场景;
参数示例:-- 如下方所示,这是订阅单个Topic的写法,第二个参数为0/1/2,默认为0;
mqttc:subscribe("/luatos/123456", 0)
-- 如下方所示,这是订阅多个Topic的写法;
mqttc:subscribe({["/luatos/1234567"]=1,["/luatos/12345678"]=2})
返回值
local mqtt_sub_result = mqttc:subscribe(topic, qos)
有一个返回值 mqtt_sub_result;
mqtt_sub_result
含义说明:判断订阅主题请求接口是否成功;当请求成功时,返回一个整数类型的消息ID,这个ID在Qos为1/2时有效;当底层返回失败时,返回nil;
数据类型:number/nil;
取值范围:无特别限制;
注意事项:底层失败时返回nil,需做好空值判断;
该返回值仅表示订阅请求发送成功 ,而非服务器已确认订阅成功,若要判断订阅是否真正成功,可通过注册事件回调函数mqttc:on(cb)来监听服务器的订阅确认;
示例
-- 订阅单个主题(topic), 且qos=0
mqttc:subscribe("/luatos/123456", 0)
-- 订阅单个(topic), 且qos=1
mqttc:subscribe("/luatos/12345678", 1)
-- 订阅多个(topic), 且使用不同的qos
mqttc:subscribe({["/luatos/1234567"]=1,["/luatos/12345678"]=2})
mqttc:publish(topic, data, qos, retain)
功能
向指定的 MQTT 主题发布消息;
注意事项
1. 调用此接口前,必须确保 mqtt 客户端已经成功连接到服务器,否则发布操作可能失败;
2. 遵循 mqtt 主题命名规范,避免使用特殊字符导致的兼容性问题;
参数
topic
参数含义:表示mqtt消息发布的主题,用于标识消息的类别或目的地;
数据类型:string;
取值范围:根据MQTT 3.1.1标准协议,最小长度为1字节,最大长度为65535字节。LuatOS对此不做限制;
是否必选:必须传入此参数;
注意事项:主题命名应遵循mqtt协议规范,避免使用特殊字符导致路由异常;
参数示例:-- 如下方所示,/luatos/123456是发送数据时的发布主题,123是发送的数据内容;
mqttc:publish("/luatos/123456", "123")
data
参数含义:表示要发布的mqtt消息内容,是消息的实际负载数据;
数据类型:string/zbuff;
取值范围:无特定限制,允许为空;
是否必选:必须传入此参数;
注意事项:仅支持string和zbuff两种数据类型,其他类型会打印日志"only support string or zbuff";
虽然必填,但允许传递空字符串(长度为0);
对于二进制数据或较大数据,建议使用zbuff类型以提高传输效率;
调用时如果不提供该参数或参数类型错误,可能导致底层发布函数接收到NULL数据;
参数示例:-- 如下方所示,/luatos/123456是发送数据时的发布主题,123是发送的数据内容;
mqttc:publish("/luatos/123456", "123")
-- 如下方所示,/luatos/123456是发送数据时的发布主题,data参数允许为空;
mqttc:publish("/luatos/123456", "")
qos
参数含义:表示mqtt消息的服务质量级别,用于控制消息传递的可靠性;
数据类型:number;
取值范围:0/1,默认为0;
是否必选:可选传入此参数,不填时,默认为0;
注意事项:如果不提供该参数,默认使用qos 0;
参数示例:-- 如下方所示,qos参数不填时,默认为0;
mqttc:publish("/luatos/123456", "123")
-- 如下方所示,设置qos参数为1;
mqttc:publish("/luatos/123456", "123", 1)
retain
参数含义:用于控制mqtt消息是否被服务器保留,当设置为保留模式时,服务器会保存该主题的最新消息,并在新客户端订阅该主题时自动发送此消息;
数据类型:number;
取值范围:0/1,默认为0;
是否必选:可选传入此参数,不填时,默认为0;
注意事项:服务器对每个主题只保留最新的一条保留消息,新的保留消息会覆盖旧的;
使用保留消息会增加服务器的存储开销,应根据实际需求谨慎使用;
参数示例:-- 如下方所示,retain参数不填时,默认为0;
mqttc:publish("/luatos/123456", "123")
-- 如下方所示,retain参数设置为1,意为服务器保留该消息;
mqttc:publish("/luatos/123456", "123", , 1)
返回值
local mqtt_pub_result = mqttc:publish(topic, data, qos, retain)
有一个返回值 mqtt_pub_result
mqtt_pub_result
含义说明:用于跟踪消息的发布状态;
数值类型:number;
取值范围:成功时,返回一个整数类型的消息ID;
失败时,返回nil;
注意事项:当消息发布失败时,接口会返回nil,建议在实际使用中对nil进行判断处理;
当qos为1或2时,返回的消息ID为有效值,可用于跟踪消息确认状态;
当qos为0时,虽然仍会返回消息ID,但由于qos 0是“最多一次”传输,该ID的实际意义较小;
示例
-- 如下方所示,这是一个基本用法,只设置topic参数和data参数;
mqttc:publish("/luatos/123456", "123")
-- 如下方所示,这是设置qos参数为1的写法,qos为1可以保证消息至少到达一次;
mqttc:publish("/device/status", "online", 1)
-- 如下方所示,这是设置qos参数为0,retain参数为1的写法,retain为1可以使服务器保留该消息;
mqttc:publish("/device/status", "online", 0, 1)
mqttc:unsubscribe(topic)
功能
取消订阅主题(Topic);
注意事项
1. 需要确保取消订阅的主题存在,否则会取消订阅失败;
2. 多主题取消订阅下,只要有任一主题取消订阅失败,整体返回 nil,需注意处理;
参数
topic
参数含义:取消订阅主题时的主题名称;
数据类型:string/table;
取值范围:根据MQTT 3.1.1标准协议,最小长度为1字节,最大长度为65535字节。LuatOS对此不做限制;
是否必选:必须传入此参数;
注意事项:取消订阅的主题必须与之前订阅的主题完全匹配(包括通配符),MQTT协议不支持部分匹配或模糊取消订阅;
参数示例:-- 如下方所示,这是取消订阅单个主题(Topic)的写法,“/luatos/123456” 为取消订阅的主题名;
mqttc:unsubscribe("/luatos/123456")
-- 如下方所示,这是取消订阅多个主题(Topic)的写法,“/luatos/1234567” 和 “/luatos/12345678” 为取消订阅的两个不同主题名;
mqttc:unsubscribe({"/luatos/1234567","/luatos/12345678"})
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 取消订阅单个主题(Topic);
mqttc:unsubscribe("/luatos/123456")
-- 取消订阅多个主题(Topic);
mqttc:unsubscribe({"/luatos/1234567","/luatos/12345678"})
mqttc:disconnect()
功能
用于断开与 mqtt 服务器的连接,但不会释放 mqtt 客户端的资源。
注意事项
1. 该接口仅断开与服务器的连接,但 不会释放 MQTT 客户端实例的资源 (如内存、配置等)
参数
无;
返回值
local mqtt_disconnect_result = mqttc:disconnect()
有一个返回值 mqtt_disconnect_result
mqtt_disconnect_result
含义说明:表示mqtt断开连接操作是否已发起
数值类型:boolean;
取值范围:true/false;
注意事项:返回值仅表示断开连接操作已发起,不代表断开连接操作是否真正成功完成;
即使返回true,也不意味着资源已被释放;
如需确认是否真正断开连接,建议通过注册disconnect事件回调或检查连接状态来判断;
示例
-- 断开连接
mqttc:disconnect()
mqttc:close()
功能
关闭 mqtt 客户端连接并释放相关资源;
注意事项
1. 调用 close()后,mqtt 客户端相关的所有资源(包括套接字、回调函数引用等)都会被释放;
2. 释放资源后,该 mqtt 客户端实例将无法再使用,若需要重新连接 mqtt 服务器,必须创建新的客户端实例;
3. 此操作是不可逆的,一旦调用,无法通过任何方式恢复客户端的功能;
参数
无;
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,不再需要连接时,关闭客户端并释放资源;
mqttc:close()
mqttc:state()
功能
获取 mqtt 客户端的当前状态,返回一个代表不同连接阶段或状态的整数值;
注意事项
1. 状态码仅反映客户端内部的状态标记,不保证与实际网络连接状态完全一致;
2. 在使用状态码进行逻辑判断时,建议使用常量而非硬编码的数字,以提高代码可维护性;
3. 与 mqttc:ready()类似,即使返回就绪状态,实际的发布/订阅操作仍可能因网络问题失败;
参数
无;
返回值
local mqtt_state = mqttc:state()
有一个返回值 mqtt_state
mqtt_state
含义说明:返回客户端当前的状态码,对应不同的mqtt客户端状态;
数值类型:number;
取值范围:状态码 0,宏定义 MQTT_STATE_DISCONNECT,表示断开连接状态,即客户端未连接到服务器,或已主动/被动断开连接;
状态码 1,宏定义 MQTT_STATE_CONNECTING,表示连接进行中,即客户端正在尝试与服务器建立连接;
状态码 2,宏定义 MQTT_STATE_CONNECTED,表示已连接到服务器,即客户端已成功与服务器建立连接,但可能尚未完全就绪;
状态码 3,宏定义 MQTT_STATE_READY,表示就绪状态,即客户端已完全就绪,可以进行发布/订阅等操作;
状态码 4,宏定义 MQTT_STATE_ERROR,表示错误状态,即客户端遇到错误,可能需要重新初始化或检查网络连接;
注意事项:返回的状态码仅反映客户端内部的状态标记,不保证与实际网络连接状态完全一致,即使返回已连接状态,网络连接仍可能已经断开但客户端尚未检测到;
建议在使用时通过宏定义或常量而非硬编码的数字来引用状态,以提高代码的可维护性;
示例
-- 如下方所示,为mqttc:state()接口的基础用法;
local mqtt_state = mqttc:state()
-- 记录当前状态
log.info("MQTT", "当前状态:", state)
-- 根据不同状态执行不同操作
if mqtt_state == 0 then -- DISCONNECT
log.info("MQTT", "未连接,尝试重连...")
-- 可调用mqttc:connect()重新连接
elseif mqtt_state == 1 then -- CONNECTING
log.info("MQTT", "连接中,请稍候...")
elseif mqtt_state == 2 then -- CONNECTED
log.info("MQTT", "已连接到服务器")
elseif mqtt_state == 3 then -- READY
log.info("MQTT", "客户端就绪,可以发布消息")
elseif mqtt_state == 4 then -- ERROR
log.error("MQTT", "客户端错误,需要重新初始化")
-- 执行错误处理逻辑
end
五、产品支持说明
支持 LuatOS 开发的所有产品都支持 mqtt 核心库。