设备连接失败有多种原因,例如设备与云端网络连接不通,设备鉴权失败,无线网络信号问题导致超时等,可根据设备连接过程 SDK 的错误日志类型来区分处理,一般处理步骤如下:
/* default MQTT/CoAP timeout value when connect/pub/sub (unit: ms) */
#define QCLOUD_IOT_MQTT_COMMAND_TIMEOUT (5 * 1000)
物联网接入层有设备互踢的逻辑,如果是用同一个设备 ID 在不同地方登录,会导致其中一方被另一方踢下线。因此发现设备一直上下线时,需要确认是否有不同的人或者多线程在使用同一个设备 ID 执行登录操作。
可以通过产品信息中的消息队列对设备状态变化通知进行设置,设置完成后即可将设备状态变化的通知主动推送到对应的消息队列中。
一般有几类原因:
使用设备端 SDK 建立 MQTT 连接时。如果初始化参数开启了自动重连(默认开启),那么会进行自动重连的操作。在 SDK 的 Yield 函数中,会根据报文收发以及心跳包行为是否正常来判断网络连接状况,如果出现连接断开情况,会自动进行重连。同时为了避免在网络故障情况下频繁进行重连,SDK 的重连间隔是动态变化的,从最小值开始,如果重连失败,重连间隔就会翻倍增长,如果重连间隔达到最大值后仍然还是连接失败则返回重连超时错误。
如果是用户手动断开连接的情况,如主动调用 Destroy 函数,则不会进行自动重连。
在 qcloud_iot_export_variables.h 里面有重连间隔最大值的默认设置:
/* MAX MQTT reconnect interval (unit: ms) */
#define MAX_RECONNECT_WAIT_INTERVAL (60 * 1000)
采用远程依赖的方式编译出错的话,可能会由于远程库更新不及时导致编译出错。可以在gradle文件中将依赖方式修改成本地库依赖:
有如下建议:
MQTT 采用 TCP 长连接,需要心跳包机制来保证连接是活跃的,设备端 C-SDK 按照 MQTT 规范的 Keep Alive 机制,在 qcloud_iot_export_variables.h 里面有一个心跳包发送周期的默认设置:
/* default MQTT keep alive interval (unit: ms) */
#define QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL (240 * 1000)
在一个心跳发送周期内,如果设备端没有成功发送 MQTT 控制报文(包括 SUB/UNSUB/QoS1 PUB 报文,并收到相应的ACK),则会发送 MQTT PINGREQ 给云端并等待云端回复 PINGRESP 报文,如果在一定时间内没有收到 PINGRESP 报文,则设备端认为连接已断开,会进行自动重连操作。
目前物联网通信平台支持 MQTT QoS0 和 QoS1,不支持 QoS2。对于 QoS0 的消息,设备端在 Publish 函数调用返回成功之后,即由 TCP/IP 协议栈来保障消息是否送达,SDK 不会做进一步处理。而对于 QoS1 的消息,SDK 会维护一个消息状态队列,并根据 MQTT PUBACK 消息做进一步的跟踪反馈,并在相应的事件回调中通知用户该 QoS1 消息是成功送达或者超时失败,再由用户决定是否进行重发。
Yield 函数的作用是在当前线程上下文中,进行 MQTT 报文读取,消息处理,超时请求,心跳包及重连状态管理等任务,是设备端进行 MQTT 物联网通信的重要步骤。对于单线程单任务场景,在用户的逻辑代码循环中需要保证对该函数的调用执行。对于多线程多任务场景,可以使用一个单独的线程任务来执行该函数,并且设置一定的线程优先级,避免该线程被长时间挂起。具体使用方法可以参考相应的 sample 代码。
设备端 C-SDK 支持多线程,对于 MQTT 接口在多线程环境下的使用有如下注意事项,详细代码用例请参考samples/mqtt/multi_thread_mqtt_sample.c
从版本v2.3.1开始,设备端 C-SDK 增加设备端日志上报功能,可将设备端的运行日志通过 HTTP 上报到云端,并可在控制台展示,方便用户远程诊断及监控设备运行状况。因为日志上报采用了单独的通讯通道,可以在网络通讯正常但 MQTT 连接出现问题时,进行远程诊断。
本页内容是否解决了您的问题?