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 客户端
--[[
本核心示例的的业务逻辑为:
1、创建并启动一个基础task,task名称为"mqtt_client_task_func",在task的任务处理函数内创建mqtt客户端和连接mqtt服务器,并执行一些相关操作;
2、创建并启动一个基础task,task名称为"mqtt_data_report_task_func",在task的任务处理函数内定时发布数据;
]]
PROJECT = "mqtt_test"
VERSION = "001.000.000"
-- 在日志中打印项目名和项目版本号
log.info("main", PROJECT, VERSION)
-- 配置mqtt服务器地址和端口(服务器地址支持域名和IP地址,端口号必须为有效的整数值)
-- 示例代码中填写的是合宙测试服务器地址和端口,不可用于正式环境
local SERVER_ADDR = "lbsmqtt.airm2m.com"
local SERVER_PORT = 1884
-- 配置用户名和密码
local USERNAME = "user"
local PASSWORD = "password"
-- 定义client实例对象
local mqtt_client = nil
-- mqtt client的事件回调函数
function mqtt_client_cbfunc(mqtt_client, event, data, payload, metas)
-- 每次进回调函数都打印一次这五个参数;
log.info("mqtt_client_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-- 服务器鉴权完成,表示mqtt连接已建立,可以订阅和发布数据;
if event == "conack" then
log.info("mqtt_client_cbfunc", "conack", "连接成功")
-- 此处为用户代码,可在此处订阅主题等;
-- 订阅主题
-- 订阅单主题
local mqtt_sub_result = mqtt_client:subscribe("device/" .. mobile.imei() .. "/down", 1)
if mqtt_sub_result then
log.info("mqtt_client_cbfunc", "subscribe", "订阅成功", "主题:", "device/" .. mobile.imei() .. "/down")
else
log.error("mqtt_client_cbfunc", "subscribe", "订阅失败", "主题:", "device/" .. mobile.imei() .. "/down")
end
-- 订阅多主题,如果有需要,打开注释
-- 表中的每一个订阅主题的格式为[topic] = qos
-- mqtt_sub_result = mqtt_client:subscribe({
-- [("device/" .. mobile.imei() .. "/down")] = 0,
-- [("device1/" .. mobile.imei() .. "/down")] = 1
-- })
-- if mqtt_sub_result then
-- log.info("mqtt_client_cbfunc", "subscribe", "订阅成功", "主题:", "device/" .. mobile.imei() .. "/down")
-- else
-- log.error("mqtt_client_cbfunc", "subscribe", "订阅失败", "主题:", "device/" .. mobile.imei() .. "/down")
-- end
-- 订阅完成;
-- data:订阅应答结果,true为成功,false为失败;
-- payload:成功时为0-2的整数(表示qos等级),失败时为失败码(一般是0x80);
elseif event == "suback" then
log.info("mqtt_client_cbfunc", "suback", "订阅完成")
if data then
log.info("mqtt_client_cbfunc", "suback", "订阅结果:", data, "qos:", payload)
else
log.info("mqtt_client_cbfunc", "suback", "订阅结果:", data, "失败码:", payload)
end
-- 取消订阅完成;
elseif event == "unsuback" then
log.info("mqtt_client_cbfunc", "unsuback", "取消订阅完成")
-- 接收到服务器下发的数据;
-- data:字符串类型,表示收到消息的主题;
-- payload:字符串类型,表示收到消息的业务数据内容;
-- metas:表类型,表示收到消息的元数据,数据内容格式如下:
-- {
-- message_id:数值类型,表示消息id;
-- qos:数值类型,取值范围0/1/2,表示服务器质量等级;
-- retain:数值类型,取值范围0/1,表示保留标志;
-- dup:数值类型,取值范围0/1,表示重复标志;
-- }
elseif event == "recv" then
log.info("mqtt_client_cbfunc", "recv", "收到消息", "主题:", data, "内容:", payload)
-- 打印收到消息的元数据内容;
if metas then
log.info("mqtt_client_cbfunc", "recv", "消息元数据", "qos:", metas.qos, "retain:", metas.retain)
end
-- 发送消息成功;
-- data:数值类型,表示消息id;
elseif event == "sent" then
log.info("mqtt_client_cbfunc", "sent", "发送消息成功", "消息id:", data)
-- 服务器断开mqtt连接;
-- data:数值类型,表示错误码;
elseif event == "disconnect" then
log.info("mqtt_client_cbfunc", "disconnect", "连接断开", "错误码:", data)
-- 收到服务器的心跳应答;
elseif event == "pong" then
log.info("mqtt_client_cbfunc", "pong", "收到服务器心跳应答")
-- 严重异常,本地会主动断开连接;
-- data:字符串类型,表示具体的异常,有以下几种类型:
-- "connect":表示tcp连接失败;
-- "tx":表示数据发送失败;
-- "conack":表示mqtt connect后,服务器应答CONNACK鉴权失败,错误码通过payload参数查看(数值类型);
-- "other":其他异常,错误码通过payload参数查看(数值类型);
elseif event == "error" then
log.info("mqtt_client_cbfunc", "error", "发生异常错误")
if data == "connect" then
log.info("mqtt_client_cbfunc", "error", "tcp连接失败")
elseif data == "tx" then
log.info("mqtt_client_cbfunc", "error", "数据发送失败")
elseif data == "conack" then
log.info("mqtt_client_cbfunc", "error", "服务器鉴权失败,错误码:", payload)
else
log.info("mqtt_client_cbfunc", "error", "未知错误,错误码:", payload)
end
end
-- -- 检查mqtt客户端是否已就绪
-- local mqtt_ready_result = mqtt_client:ready()
-- -- 判断mqtt客户端是否已就绪
-- if mqtt_ready_result then
-- log.info("mqtt 客户端已就绪")
-- -- 用户处理代码
-- else
-- log.info("mqtt 客户端未就绪,正在尝试重连...")
-- -- 执行重连操作
-- end
end
local function mqtt_client_state_func()
-- 每隔1秒检查一次mqtt客户端状态
-- sys.wait接口需要在task中运行
sys.wait(1000)
-- 检查mqtt客户端状态
local mqtt_state = mqtt_client:state()
-- 记录当前状态
log.info("mqtt_state", "当前状态:", mqtt_state)
-- 根据不同状态执行不同操作
if mqtt.STATE_DISCONNECT == mqtt_state then
log.info("mqtt_state", "mqtt客户端未连接,尝试重连...")
-- 可调用mqtt_client:connect接口进行重新连接
return false -- 客户端未连接,返回false
elseif mqtt.STATE_SCONNECT == mqtt_state then
log.info("mqtt_state", "建立底层socket连接中,请稍候...")
elseif mqtt.STATE_MQTT == mqtt_state then
log.info("mqtt_state", "底层socket建立成功,正在进行mqtt连接,请稍后...")
elseif mqtt.STATE_READY == mqtt_state then
log.info("mqtt_state", "mqtt客户端已就绪,可以进行发布消息、订阅主题等操作")
return true -- 客户端就绪,返回true
end
end
-- mqtt main task 的任务处理函数
local function mqtt_client_task_func()
while true do
-- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待;
while not socket.adapter(socket.dft()) do
log.info("mqtt_client_task_func", "wait IP_READY", socket.dft())
-- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
-- 或者等待1秒超时退出阻塞等待状态;
-- 注意:此处的1000毫秒超时不要修改的更长;
-- 因为当使用多网卡功能的exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
-- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
sys.waitUntil("IP_READY", 1000)
end
-- 检测到了IP_READY消息;
log.info("mqtt_client_task_func", "recv IP_READY", "适配器编号:"..socket.dft())
-- 创建mqtt客户端
mqtt_client = mqtt.create(nil, SERVER_ADDR, SERVER_PORT, false, false)
-- 判断mqtt客户端是否创建成功
if mqtt_client then
log.info("mqtt_client_task_func", "mqtt.create success", "服务器地址:", SERVER_ADDR, "服务器端口:", SERVER_PORT)
else
log.error("mqtt_client_task_func", "mqtt.create error", "服务器地址:", SERVER_ADDR, "服务器端口:", SERVER_PORT)
goto EXCEPTION_PROC
end
-- 配置是否打开debug信息,true为打开,false为关闭
mqtt_client:debug(false)
-- 配置创建mqtt客户端的client id,username,password和clean session标志
mqtt_auth_result = mqtt_client:auth("mqtt_client_"..mobile.imei(), USERNAME, PASSWORD, true)
-- 判断配置是否成功
if mqtt_auth_result then
log.info("mqtt_client_task_func", "mqtt_client:auth success", "client id:", "mqtt_client_"..mobile.imei())
else
log.error("mqtt_client_task_func", "mqtt_client:auth error", "client id:", "mqtt_client_"..mobile.imei())
goto EXCEPTION_PROC
end
-- 设置 mqtt 客户端的心跳时间间隔,单位为秒(s)
-- 如果没有设置,默认值为240秒;
-- 实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 180秒,这是系统防止因网络问题导致心跳包未在设定时间到达服务器时所执行的策略,从而确保了连接的稳定性;
-- 时间线示意图:
-- 0秒 180秒 240秒
-- |------------------|-------------------|
-- 连接建立 客户端发送PINGREQ 服务器检测超时
-- ↑ ↑
-- 预留1/4时间给服务器响应
-- 有需要的话,可以打开注释
-- mqtt_client:keepalive(120)
-- 设置遗嘱消息,有需要的话,可以打开注释
-- mqtt_will_result = mqtt_client:will("/luatos/123456", "123", 1, 0)
-- -- 如果配置失败
-- if mqtt_will_result then
-- log.info("遗嘱消息设置成功")
-- -- 继续执行连接操作;
-- else
-- log.info("遗嘱消息设置失败,请检查参数或客户端状态")
-- -- 进行错误处理;
-- end
-- 开启自动重连,间隔3秒
-- 如果项目中使用多网卡功能,一定不要使用此接口,否则内核固件在自动重连时,可能会使用错误的网卡,导致无法上网
-- mqtt_client:autoreconn(true, 3000)
-- 注册mqtt_client对象的事件回调函数
mqtt_client:on(mqtt_client_cbfunc)
-- 连接mqtt服务器
-- 本函数仅代表发起成功, 后续仍需根据mqtt_client:ready接口或注册的conack事件回调判断mqtt是否连接正常
mqtt_connect_request = mqtt_client:connect()
-- 判断连接请求是否成功
if mqtt_connect_request then
log.info("mqtt_client_task_func", "mqtt_connect_request success")
else
log.error("mqtt_client_task_func", "mqtt_connect_request error")
goto EXCEPTION_PROC
end
while true do
-- 检查mqtt客户端状态;
if mqtt_client_state_func() == false then
log.info("mqtt_client_task_func", "mqtt_client_state_func error")
goto EXCEPTION_PROC
end
-- 如果不检查mqtt客户端状态了,就把空等待循环打开;
-- sys.wait(60000000)
end
-- 出现异常
::EXCEPTION_PROC::
-- 如果存在mqtt_client对象
if mqtt_client then
-- 关闭mqtt_client,并且释放mqtt_client对象
mqtt_client:close()
mqtt_client = nil
end
-- 5秒后跳转到循环体开始位置,自动发起重连
sys.wait(5000)
end
end
-- mqtt数据定时上报任务函数
local function mqtt_data_report_task_func()
sys.wait(3000)
local data = "123,"
local qos = 1 -- QOS0不带puback, QOS1是带puback的
while true do
sys.wait(3000)
if mqtt_client and mqtt_client:ready() then
local mqtt_pub_result = mqtt_client:publish("device/" .. mobile.imei() .. "/up", data .. os.date(), qos)
-- 判断消息是否发布成功
-- if mqtt_pub_result then
-- log.info("mqtt_pub_result", "发布成功")
-- else
-- log.error("mqtt_pub_result", "发布失败")
-- end
end
end
end
-- 创建并启动一个基础task,task名称为"mqtt_client_task_func",在task的任务处理函数内创建mqtt客户端和连接mqtt服务器,并执行一些相关操作;
sys.taskInit(mqtt_client_task_func)
-- 创建并启动一个基础task,task名称为"mqtt_data_report_task_func",在task的任务处理函数内定时发布数据;
sys.taskInit(mqtt_data_report_task_func)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行
三、常量详解
核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
3.1 mqtt.STATE_DISCONNECT
常量含义:mqtt断开,表示mqtt客户端当前处于断开连接的状态,没有与mqtt服务器建立任何连接;
数据类型:number;
取值范围:0;
示例代码:-- 如下方所示,为mqtt.STATE_DISCONNECT变量的最基本写法;
if mqtt.STATE_DISCONNECT == mqttc:state() then
-- 状态:MQTT断开连接
log.info("MQTT状态", "当前状态:断开连接")
end
3.2 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
3.3 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
3.4 mqtt.STATE_READY
常量含义:mqtt mqtt已连接,表示mqtt客户端已成功完成所有连接步骤,处于完全就绪状态,可以进行发布消息、订阅主题等操作;
数据类型:number;
取值范围:3;
示例代码:-- 如下方所示,为mqtt.STATE_READY变量的最基本写法;
if mqtt.STATE_READY == mqttc:state() then
-- 状态:MQTT已完全连接就绪
log.info("MQTT状态", "当前状态:已连接就绪")
end
四、函数详解
4.1 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;
取值范围:不可超过191字符;
是否必选:必须传入此参数;
注意事项:支持字符串形式的域名或IP地址;
作为必需参数,若不提供会导致错误;
参数示例:-- 如下方所示,这是普通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的整数;
-- 是否必选:可选传入此参数,如不填,系统会根据编译时的模组型号选择对应的默认值(带psram的模组默认值为64K,不带psram的模组默认值为4K,模组是否内置psram可通过模组规格书/硬件手册自行查阅);
-- 注意事项:增大缓冲区可以提高接收大数据包的能力,但会占用更多内存;
-- 减小缓冲区可以节省内存,但可能导致大数据包接收不完整;
-- 应根据实际应用场景和设备内存资源合理设置;
-- 参数示例:rxSize = 4096;
rxSize
}
数据类型:boolean/table;
取值范围:无特别限制;
是否必选:可选传入此参数,不填时默认为ipv4协议;
注意事项:不填或为nil时,默认使用IPv4协议;
不通过rxSize参数自定义接收缓冲区大小时,系统会根据编译时的模组型号选择对应的默认值(带psram的模组默认值为64K,不带psram的模组默认值为4K,模组是否内置psram可通过模组规格书/硬件手册自行查阅);
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;
实例对象名称并不是固定的mqttc,可自定义;
数值类型: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"
})
4.2 mqttc:debug(onoff)
功能
配置是否打开 debug 信息,即控制 mqtt 客户端是否输出调试信息;
注意事项
1. 必须传入布尔类型参数 onoff(true 表示打开调试,false 表示关闭调试);
2. 建议开发调试阶段可打开,方便查看 mqtt 通信的详细过程。调试结束后应关闭,以减少不必要的日志输出;
参数
onoff
参数含义:是否打开debug信息,true表示打开调试,false表示关闭调试;
数据类型:boolean;
取值范围:true/false;
是否必选:必须传入此参数;
注意事项:必须是布尔类型(true/false);
参数示例:-- 如下方所示,传入值为true,表示打开调试;
mqttc:debug(true)
-- 如下方所示,传入值为false,表示关闭调试;
mqttc:debug(false)
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,传入值为true,表示打开调试;
mqttc:debug(true)
-- 如下方所示,传入值为true,表示关闭调试;
mqttc:debug(false)
4.3 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个字符;
是否必选:可选传入此参数,如不填,服务器会随机生成client_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模式下,服务器会强制生成一个随机的cliet_id来标识该客户端,同时mqtt协议要求cleanSession参数必须为true,因此此时如果再手动配置cleanSession参数,服务器端会直接忽略,并强制使用cleanSession参数为true的模式;
该参数的设置会直接影响客户端重连后的行为:
设置为false时,重连后服务器会推送客户端离线期间未接收的QoS 1和QoS 2消息;
设置为true时,重连后不会恢复之前的会话状态;
若服务器不支持会话保留功能,即使设置为true,也可能无法保留会话状态;
参数示例:-- 如下方所示,不手动设置cleanSession参数时默认为true;
mqttc:auth("123456789")
-- 如下方所示,手动设置cleanSession参数为false,不清除mqtt会话状态;
mqttc:auth("123456789", "username", "password", false)
-- 如下方所示,无clientId模式,服务器随机生成client_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模式的写法,此时服务器会强制生成一个随机的cliet_id来标识该客户端,同时mqtt协议要求cleanSession参数必须为true,因此此时如果再手动配置cleanSession参数,服务器端会直接忽略,并强制使用cleanSession参数为true的模式;
mqttc:auth()
-- 如下方所示,这是仅clientID的写法,无用户名密码登录;
mqttc:auth("123456789")
-- 如下方所示,这是带用户名密码登录;
mqttc:auth("123456789", "username", "password")
-- 如下方所示,这是手动配置cleanSession参数为false的写法,不清除mqtt会话状态;
mqttc:auth("123456789", "username", "password", false)
4.4 mqttc:keepalive(time)
功能
设置 mqtt 客户端的心跳时间间隔,单位为秒(s);
注意事项
1. 参数 time 为可选值,默认值为 240 秒,最小值限制为 15 秒(若传入小于 15 的值,会被强制设为 15 秒),最大值限制为 600 秒(若传入大于 600 的值,会被强制设为 600 秒);
2. 实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75,这是系统防止因网络问题导致心跳包未在设定时间到达服务器时所执行的策略,从而确保了连接的稳定性;
-- 时间线示意图:
-- 0秒 180秒 240秒
-- |------------------|-------------------|
-- 连接建立 客户端发送PINGREQ 服务器检测超时
-- ↑ ↑
-- 预留1/4时间给服务器响应
3. 建议在 mqtt 连接前设置心跳参数,也可以在连接后动态调整心跳时间;
4. 网络稳定环境可使用默认值 240 秒,或根据服务器要求调整;
5. 心跳间隔过短会增加功耗和网络流量,过长可能导致连接被服务器过早断开;
参数
time
参数含义:用于设置mqtt客户端的心跳时间间隔,即客户端向服务器发送心跳包的时间间隔;
数据类型:number;
取值范围:最小值:15秒(若传入小于15的值,会被强制设为15秒);
最大值:600秒(若传入大于600的值,会被强制设为600秒);
是否必选:可选传入此参数,若不传入,默认值为240秒;
注意事项:单位为秒(s),无需额外转换单位;
传入值会被自动截断到有效范围内(15-600秒);
实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75,这是系统防止因网络问题导致心跳包未在设定时间到达服务器时所执行的策略,从而确保了连接的稳定性;
-- 时间线示意图:
-- 0秒 180秒 240秒
-- |------------------|-------------------|
-- 连接建立 客户端发送PINGREQ 服务器检测超时
-- ↑ ↑
-- 预留1/4时间给服务器响应
心跳间隔过短会增加设备功耗和网络流量,过长可能导致连接被服务器过早判定为断开;
该参数可在连接前或连接后设置,连接后设置会覆盖之前的值;
参数示例:-- 如下方所示,这是使用默认值240秒的写法,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 180秒;
mqttc:keepalive()
-- 如下方所示,这是设置为30秒的写法,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 22.5秒;
mqttc:keepalive(30)
-- 如下方所示,传入超出范围的值会被截断;
mqttc:keepalive(10) -- 实际生效为15秒,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 11.25秒;
mqttc:keepalive(800) -- 实际生效为600秒,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 450秒;
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,这是使用默认值240秒的写法,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 180秒;
mqttc:keepalive()
-- 如下方所示,这是设置为30秒的写法,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 22.5秒;
mqttc:keepalive(30)
-- 如下方所示,传入超出范围的值会被截断;
mqttc:keepalive(10) -- 实际生效为15秒,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 11.25秒;
mqttc:keepalive(800) -- 实际生效为600秒,实际发送心跳时间间隔 = 设置的心跳时间间隔 × 0.75 = 450秒;
4.5 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")
-- 注意:必须在connect前设置;
mqttc:connect()
payload
参数含义:mqtt客户端设置的遗嘱消息内容;
数据类型:string;
取值范围:无特别限制;
是否必选:必须传入此参数;
注意事项:必须在调用mqttc:connect()之前设置,否则无效;
如果包含非ASCII字符,需要确保编码格式与接收端一致;
topic和payload共同构成完整的遗嘱消息,应合理设计两者内容;
参数示例:-- 如下方所示,需要在调用mqttc:connect()之前设置,否则无效;
mqttc:will("/luatos/123456", "123")
-- 注意:必须在connect前设置;
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("遗嘱消息设置成功")
-- 继续执行连接操作;
else
log.info("遗嘱消息设置失败,请检查参数或客户端状态")
-- 进行错误处理;
end
4.6 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)
4.7 mqttc:on(cb)
功能
注册 mqtt 客户端事件回调函数的接口;
注意事项
1. 回调函数应保持简洁高效 ,避免执行耗时操作(如复杂计算、阻塞 IO 等),否则可能影响 mqtt 客户端的消息处理实时性;
参数
cb
参数含义:mqtt事件回调函数;回调函数的格式为:
function callback(mqtt_client, event, data, payload, metas)
log.info("callback", mqtt_client, event, data, payload, json.encode(metas))
end
该回调函数接收mqtt_client、event、data、payload、metas五个参数,在不同事件类型下参数含义有所不同:
-- 参数含义:mqtt客户端对象本身;
-- 数据类型:string;
-- 取值范围:无限制;
-- 是否必选:必须传入此参数;
-- 注意事项:所有事件类型都会传递此参数,可用于在回调中操作客户端(如重连、发布消息等);
mqtt_client
-- 参数含义:事件类型标识符;
-- 数据类型:string;
-- 取值范围:
"conack" -- 当event参数的值为"conack"时,表示服务器鉴权完成,mqtt连接已建立,可以订阅和发布数据;
"suback" -- 当event参数的值为"suback"时,表示客户端订阅主题完成;
"unsuback" -- 当event参数的值为"unsuback"时,表示客户端取消订阅主题完成;
"recv" -- 当event参数的值为"recv"时,表示客户端接收到服务器下发的消息;
"sent" -- 当event参数的值为"sent"时,表示客户端发送消息完成;
"disconnect" -- 当event参数的值为"disconnect"时,表示mqtt连接已断开;
"pong" -- 当event参数的值为"pong"时,表示客户端收到服务器心跳应答;
"error" -- 当event参数的值为"error"时,表示发生严重异常,会导致断开连接;
-- 是否必选:必须传入此参数;
-- 注意事项:用于标识当前触发的mqtt事件类型,是回调函数中判断事件类型的核心依据;
event
-- 参数含义:事件相关的数据;
-- 数据类型:根据event类型不同而变化;
-- 取值范围:根据event类型不同而变化:
"conack" -- 当event参数的值为"conack"时,data参数无实际数据,实际打印时为"nil";
"suback" -- 当event参数的值为"suback"时,data参数的值表示客户端订阅主题完成状态,数据类型为布尔值(true表示客户端订阅主题成功,false表示客户端订阅主题失败);
"unsuback" -- 当event参数的值为"unsuback"时,data参数无实际数据,实际打印时为"nil";
"recv" -- 当event参数的值为"recv"时,data参数的值表示客户端收到服务器下发消息时的主题(topic),数据类型为字符串;
"sent" -- 当event参数的值为"sent"时,data参数的值表示客户端发送消息时的消息id,数据类型为数值型;
"disconnect" -- 当event参数的值为"disconnect"时,data参数无实际数据,实际打印时为"nil";
"pong" -- 当event参数的值为"pong"时,data参数无实际数据,实际打印时为"nil";
"error" -- 当event参数的值为"error"时,data参数的取值范围有以下四种,数据类型为字符串:
"connect" -- 当data参数的值为"connect"时,表示客户端连接不上服务器;
"tx" -- 当data参数的值为"tx"时,表示客户端发送数据失败;
"conack" -- 当data参数的值为"conack"时,表示服务器鉴权失败;
"other" -- 当data参数的值为"other"时,表示其他异常情况;
-- 是否必选:可选传入此参数;
-- 注意事项:不同事件类型下数据类型和含义不同,需根据事件类型进行相应处理;
data
-- 参数含义:业务数据或结果码;
-- 数据类型:根据event类型不同而变化;
-- 取值范围:根据event类型不同而变化;
"conack" -- 当event参数的值为"conack"时,payload参数无实际数据,实际打印时为"nil";
"suback" -- 当event参数的值为"suback"时,payload参数的值根据客户端订阅主题是否成功分为两种,当客户端订阅主题成功时payload参数的取值为0-2的整数(表示qos等级),当客户端订阅主题失败时payload参数的取值为失败码(一般是0x80);
"unsuback" -- 当event参数的值为"unsuback"时,payload参数无实际数据,实际打印时为"nil";
"recv" -- 当event参数的值为"recv"时,payload参数的值表示收到的业务数据内容,数据类型为字符串;
"sent" -- 当event参数的值为"sent"时,payload参数无实际数据,实际打印时为"nil";
"disconnect" -- 当event参数的值为"disconnect"时,payload参数无实际数据,实际打印时为"nil";
"pong" -- 当event参数的值为"pong"时,payload参数无实际数据,实际打印时为"nil";
"error" -- 当event参数的值为"error"时,且data参数的值为"conack"时,payload参数的值表示整数失败码,data参数的值为其他类型时,payload参数无实际数据,实际打印时为"nil";
-- 是否必选:可选传入此参数;
-- 注意事项:通常与data参数配合使用,提供更详细的事件信息;
payload
-- 参数含义:消息元数据(仅在特定事件中存在)
-- 数据类型:table;
-- 取值范围:仅当event参数的值为"recv"时,metas参数的取值才有意义,event参数的值为其他类型时,metas参数无实际数据,实际打印时为"nil";
message_id -- 消息id;
qos -- 服务器质量等级,取值范围0、1、2;
retain -- 保留标志,取值范围0、1;
dup -- 重复标志,取值范围0、1;
-- 是否必选:可选传入此参数;
-- 注意事项:仅部分事件类型提供,主要用于获取消息的元数据信息,一般情况下可根据需要选择性处理;
metas
数据类型:function;
取值范围:回调函数本身无取值范围这一说法;
是否必选:必须传入此参数;
注意事项:每次调试会覆盖之前注册的回调函数;
参数示例:-- 如下方所示,这是注册mqtt客户端的事件回调函数写法;
function mqtt_client_cbfunc(mqtt_client, event, data, payload, metas)
-- 每次进回调函数都打印一次这五个参数;
log.info("mqtt_client_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-- 服务器鉴权完成,表示mqtt连接已建立,可以订阅和发布数据;
if event == "conack" then
log.info("mqtt_client_cbfunc", "conack", "连接成功")
-- 此处为用户代码,可在此处订阅主题等;
-- 订阅完成;
-- data:订阅应答结果,true为成功,false为失败;
-- payload:成功时为0-2的整数(表示qos等级),失败时为失败码(一般是0x80);
elseif event == "suback" then
log.info("mqtt_client_cbfunc", "suback", "订阅完成")
if data then
log.info("mqtt_client_cbfunc", "suback", "订阅结果:", data, "qos:", payload)
else
log.info("mqtt_client_cbfunc", "suback", "订阅结果:", data, "失败码:", payload)
end
-- 取消订阅完成;
elseif event == "unsuback" then
log.info("mqtt_client_cbfunc", "unsuback", "取消订阅完成")
-- 接收到服务器下发的数据;
-- data:字符串类型,表示收到消息的主题;
-- payload:字符串类型,表示收到消息的业务数据内容;
-- metas:表类型,表示收到消息的元数据,数据内容格式如下:
-- {
-- message_id:数值类型,表示消息id;
-- qos:数值类型,取值范围0/1/2,表示服务器质量等级;
-- retain:数值类型,取值范围0/1,表示保留标志;
-- dup:数值类型,取值范围0/1,表示重复标志;
-- }
elseif event == "recv" then
log.info("mqtt_client_cbfunc", "recv", "收到消息", "主题:", data, "内容:", payload)
-- 打印收到消息的元数据内容;
if metas then
log.info("mqtt_client_cbfunc", "recv", "消息元数据", "qos:", metas.qos, "retain:", metas.retain)
end
-- 发送消息成功;
-- data:数值类型,表示消息id;
elseif event == "sent" then
log.info("mqtt_client_cbfunc", "sent", "发送消息成功", "消息id:", data)
-- 服务器断开mqtt连接;
-- data:数值类型,表示错误码;
elseif event == "disconnect" then
log.info("mqtt_client_cbfunc", "disconnect", "连接断开", "错误码:", data)
-- 收到服务器的心跳应答;
elseif event == "pong" then
log.info("mqtt_client_cbfunc", "pong", "收到服务器心跳应答")
-- 严重异常,本地会主动断开连接;
-- data:字符串类型,表示具体的异常,有以下几种类型:
-- "connect":表示tcp连接失败;
-- "tx":表示数据发送失败;
-- "conack":表示mqtt connect后,服务器应答CONNACK鉴权失败,错误码通过payload参数查看(数值类型);
-- "other":其他异常,错误码通过payload参数查看(数值类型);
elseif event == "error" then
log.info("mqtt_client_cbfunc", "error", "发生异常错误")
if data == "connect" then
log.info("mqtt_client_cbfunc", "error", "tcp连接失败")
elseif data == "tx" then
log.info("mqtt_client_cbfunc", "error", "数据发送失败")
elseif data == "conack" then
log.info("mqtt_client_cbfunc", "error", "服务器鉴权失败,错误码:", payload)
else
log.info("mqtt_client_cbfunc", "error", "未知错误,错误码:", payload)
end
end
end
-- 注册mqtt事件回调函数接口,mqtt_client_cbfunc为回调函数;
mqttc:on(mqtt_client_cbfunc)
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,这是注册mqtt客户端的事件回调函数写法;
function mqtt_client_cbfunc(mqtt_client, event, data, payload, metas)
-- 每次进回调函数都打印一次这五个参数;
log.info("mqtt_client_cbfunc", mqtt_client, event, data, payload, json.encode(metas))
-- 服务器鉴权完成,表示mqtt连接已建立,可以订阅和发布数据;
if event == "conack" then
log.info("mqtt_client_cbfunc", "conack", "连接成功")
-- 此处为用户代码,可在此处订阅主题等;
-- 订阅完成;
-- data:订阅应答结果,true为成功,false为失败;
-- payload:成功时为0-2的整数(表示qos等级),失败时为失败码(一般是0x80);
elseif event == "suback" then
log.info("mqtt_client_cbfunc", "suback", "订阅完成")
if data then
log.info("mqtt_client_cbfunc", "suback", "订阅结果:", data, "qos:", payload)
else
log.info("mqtt_client_cbfunc", "suback", "订阅结果:", data, "失败码:", payload)
end
-- 取消订阅完成;
elseif event == "unsuback" then
log.info("mqtt_client_cbfunc", "unsuback", "取消订阅完成")
-- 接收到服务器下发的数据;
-- data:字符串类型,表示收到消息的主题;
-- payload:字符串类型,表示收到消息的业务数据内容;
-- metas:表类型,表示收到消息的元数据,数据内容格式如下:
-- {
-- message_id:数值类型,表示消息id;
-- qos:数值类型,取值范围0/1/2,表示服务器质量等级;
-- retain:数值类型,取值范围0/1,表示保留标志;
-- dup:数值类型,取值范围0/1,表示重复标志;
-- }
elseif event == "recv" then
log.info("mqtt_client_cbfunc", "recv", "收到消息", "主题:", data, "内容:", payload)
-- 打印收到消息的元数据内容;
if metas then
log.info("mqtt_client_cbfunc", "recv", "消息元数据", "qos:", metas.qos, "retain:", metas.retain)
end
-- 发送消息成功;
-- data:数值类型,表示消息id;
elseif event == "sent" then
log.info("mqtt_client_cbfunc", "sent", "发送消息成功", "消息id:", data)
-- 服务器断开mqtt连接;
-- data:数值类型,表示错误码;
elseif event == "disconnect" then
log.info("mqtt_client_cbfunc", "disconnect", "连接断开", "错误码:", data)
-- 收到服务器的心跳应答;
elseif event == "pong" then
log.info("mqtt_client_cbfunc", "pong", "收到服务器心跳应答")
-- 严重异常,本地会主动断开连接;
-- data:字符串类型,表示具体的异常,有以下几种类型:
-- "connect":表示tcp连接失败;
-- "tx":表示数据发送失败;
-- "conack":表示mqtt connect后,服务器应答CONNACK鉴权失败,错误码通过payload参数查看(数值类型);
-- "other":其他异常,错误码通过payload参数查看(数值类型);
elseif event == "error" then
log.info("mqtt_client_cbfunc", "error", "发生异常错误")
if data == "connect" then
log.info("mqtt_client_cbfunc", "error", "tcp连接失败")
elseif data == "tx" then
log.info("mqtt_client_cbfunc", "error", "数据发送失败")
elseif data == "conack" then
log.info("mqtt_client_cbfunc", "error", "服务器鉴权失败,错误码:", payload)
else
log.info("mqtt_client_cbfunc", "error", "未知错误,错误码:", payload)
end
end
end
-- 注册mqtt事件回调函数接口,mqtt_client_cbfunc为回调函数;
mqttc:on(mqtt_client_cbfunc)
4.8 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事件回调来确认连接是否真正建立;
示例
-- 连接mqtt服务器
-- 本函数仅代表发起成功, 后续仍需根据mqttc:ready接口或注册的conack事件回调判断mqtt是否连接正常
mqtt_connect_request = mqtt_client:connect()
-- 判断连接请求是否成功
if mqtt_connect_request then
log.info("mqtt_client_task_func", "mqtt_connect_request success")
else
log.error("mqtt_client_task_func", "mqtt_connect_request error")
end
4.9 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()
-- 判断mqtt客户端是否已就绪
if mqtt_ready_result then
log.info("mqtt 客户端已就绪")
-- 用户处理代码
else
log.info("mqtt 客户端未就绪,正在尝试重连...")
-- 执行重连操作
end
4.10 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的写法,第二个参数为qos等级,默认为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来监听服务器的订阅确认;
示例
-- 订阅单个主题(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})
4.11 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
参数含义:服务质量等级,决定了一条消息最多被送达一次、至少被送达一次,还是恰好被送达一次;
qos 0(最多一次):消息可能丢失,也可能因为网络层或中间件的意外重放而出现重复,但mqtt协议本身不会主动再发一次;
qos 1(至少一次):发送端会一直重试,直到收到接收端的PUBACK确认,因此消息至少送达一次,但也可能因确认丢失而被重复投递;
数据类型:number;
取值范围:0/1,默认为0;
是否必选:可选传入此参数,不填时,默认为0;
注意事项:如果不提供该参数,默认使用qos 0;
该接口的qos等级取值范围仅支持0或1;
参数示例:-- 如下方所示,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进行判断处理;
当消息发布成功时,接口会返回消息ID,此时仅表示消息发送请求成功,不能表示消息已经成功发送到服务器,要确认消息是否真正到达服务器,需要结合qos级别和响应的确认机制:
qos为1时,可以通过mqttc:on注册回调接口确认,在收到服务器确认时会得到通知;
qos为0时,无法直接确认消息是否到达服务器,只能依赖应用层确认机制,应用层确认机制的核心思想是“发送方发送消息并记录发送状态,接收方收到消息后主动发送一条确认消息,发送方在指定时间内未收到确认则重新发送原消息”,这样便可以实现消息的可靠传递;
示例
-- 如下方所示,这是一个基本用法,只设置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)
4.12 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"})
4.13 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()
4.14 mqttc:close()
功能
关闭 mqtt 客户端连接并释放相关资源;
注意事项
1. 调用 close() 后,mqtt 客户端相关的所有资源(包括套接字、回调函数引用等)都会被释放;
2. 释放资源后,该 mqtt 客户端实例将无法再使用,若需要重新连接 mqtt 服务器,必须创建新的客户端实例;
3. 此操作是不可逆的,一旦调用,无法通过任何方式恢复客户端的功能;
参数
无;
返回值
该接口无返回值,只需调用该接口执行相关操作,无需处理返回结果;
如果一定要把接口调用的结果赋值给一个变量,则这个变量就是一个nil值;
示例
-- 如下方所示,不再需要连接时,关闭客户端并释放资源;
mqttc:close()
4.15 mqttc:state()
功能
获取 mqtt 客户端的当前状态,返回一个代表不同连接阶段或状态的整数值;
注意事项
1. 状态码仅反映客户端内部的状态标记,不保证与实际网络连接状态完全一致;
2. 在使用状态码进行逻辑判断时,建议使用常量而非硬编码的数字,以提高代码可维护性;
3. 与 mqttc:ready() 类似,即使返回就绪状态,实际的发布/订阅操作仍可能因网络问题失败;
参数
无;
返回值
local mqtt_state = mqttc:state()
有一个返回值 mqtt_state
mqtt_state
含义说明:返回客户端当前的状态码,对应不同的mqtt客户端状态;
数值类型:number;
取值范围:状态码 0,对应常量 mqtt.STATE_DISCONNECT,表示mqtt客户端当前处于断开连接的状态,没有与mqtt服务器建立任何连接;
状态码 1,对应常量 mqtt.STATE_SCONNECT,表示mqtt客户端正在尝试建立底层socket连接,但尚未完成连接过程;
状态码 2,对应常量 mqtt.STATE_MQTT,表示底层socket连接已成功建立,但mqtt协议层面的连接(如发送CONNECT消息、等待CONNACK响应)正在进行中;
状态码 3,对应常量 mqtt.STATE_READY,表示mqtt客户端已成功完成所有连接步骤,处于完全就绪状态,可以进行发布消息、订阅主题等操作;
注意事项:返回的状态码仅反映客户端内部的状态标记,不保证与实际网络连接状态完全一致,即使返回已连接状态,网络连接仍可能已经断开但客户端尚未检测到;
建议在使用时通过常量而非硬编码的数字来引用状态,以提高代码的可维护性;
示例
-- 如下方所示,为mqttc:state接口的基础用法;
local mqtt_state = mqttc:state()
-- 记录当前状态
log.info("mqtt_state", "当前状态:", mqtt_state)
-- 根据不同状态执行不同操作
if mqtt.STATE_DISCONNECT == mqtt_state then
log.info("mqtt_state", "mqtt客户端未连接,尝试重连...")
-- 可调用mqttc:connect接口进行重新连接
elseif mqtt.STATE_SCONNECT == mqtt_state then
log.info("mqtt_state", "建立底层socket连接中,请稍候...")
elseif mqtt.STATE_MQTT == mqtt_state then
log.info("mqtt_state", "底层socket建立成功,正在进行mqtt连接,请稍后...")
elseif mqtt.STATE_READY == mqtt_state then
log.info("mqtt_state", "mqtt客户端已就绪,可以进行发布消息、订阅主题等操作")
end
五、产品支持说明
支持 LuatOS 开发的所有产品都支持 mqtt 核心库。