05.腾讯云物联网设备端学习---MQTT协议客户端实现

本系列主要目的在于记录腾讯云物联网设备端的学习笔记,并且对设备端SDK进行补充说明。

源码概述

相关源码文件请参见 https://github.com/tencentyun/qcloud-iot-explorer-sdk-embedded-c/tree/master/sdk_src/protocol/mqtt

mqtt 客户端源码概述

mqtt协议客户端主要是实现对于各个控制包的构建发送以及服务器回复的处理,其中所有的下行数据(除了connack),通过qcloud_iot_mqtt_yield进行接收并处理,订阅、取消订阅和发布通过对外提供接口由用户调用实现。

常规的流程为(在多线程下 Yiled通常使用单独的线程进行,请参见_mqtt_yield_thread):

SDK API调用常规流程

实现细节

  • CONNECT:CONNECT控制包的构建在 _serialize_connect_packet 中,其中主要是根据鉴权方式设置usrname和password,以及clean session。
  • CONNACK:CONNECT控制包发送完后会通过wait_for_read等待CONNACK,然后调用_deserialize_connack_packet进行结果判断
  • SUBSCRIBE:SUBSCRIBE控制包构建在_serialize_subscribe_packet。对于订阅,会调用push_sub_info_to加入到订阅队列list_sub_wait_ack中,然后在qcloud_iot_mqtt_yield中调用qcloud_iot_mqtt_sub_info_proc进行队列中订阅的超时判断或者收到SUBACK后的处理。其中比较关键的是SubTopicHandleon_message_handler(处理订阅主题的下行消息)和on_sub_event_handler(处理超时等事件)。
  • SUBACK:SUBACK会通过qcloud_iot_mqtt_yield接收并处理,主要根据协议判断回复是否正常
  • UNSUBSCRIBEUNSUBACK:和SUBSCRIBE处理类似,也是加入到list_sub_wait_ack中,不过实际场景中很少会用到,一般设备订阅关系在设计的时候就确定了,很少出现中途需要取消订阅的场景。
  • PUBLISH(客户端->服务器)&PUBACK:PUBLISH控制包构建在_serialize_publish_packet,通常我们只会指定QoS等级以及payload。对于QoS1的消息,会调用_mask_push_pubInfo_to加入到list_pub_wait_ack中,然后在qcloud_iot_mqtt_yield中调用qcloud_iot_mqtt_pub_info_proc队列中发布的超时判断或者收到PUBACK的处理。其中比较关键的是Qcloud_IoT_Client中的event_handle会告知发布超时,从而在应用层实现QoS1的重发。实际应用中,即使使用QoS1也无法保证消息一定能到达,因为大部分情况下无法收到PUBACK都是因为设备断网,这个时候需要应用层设计策略来实现,比如将消息存储在本地等。
  • PUBLISH(服务器->客户端)&PUBACK:服务器发送的PUBLISH消息会在qcloud_iot_mqtt_yield中调用_handle_publish_packet处理,根据QoS回复PUBACK,然后将消息回调到SubTopicHandleon_message_handler进行消息处理。
  • PINGREQ&PING:保活消息在qcloud_iot_mqtt_yield调用_mqtt_keep_alive进行发送,然后通过_handle_pingresp_packet对回复进行处理。
  • DISCONNECT:该消息通常不需要,可以参考qcloud_iot_mqtt_disconnect

一些参数

在客户端MQTT实现中会有一些参数跟实际应用相关,需要进行调整才能满足业务的需求,以下列举下:

  • QCLOUD_IOT_MQTT_MAX_REMAIN_WAIT_MS :头部接收等待最大时长,在弱网下此处需要设置较大
  • QCLOUD_IOT_MQTT_COMMAND_TIMEOUT:MQTT阻塞调用的超时时间,包括连接等,弱网下可设置较大
  • QCLOUD_IOT_MQTT_KEEP_ALIVE_INTERNAL:保活默认时间,一般来说通过API传入参数修改即可,此处只是提供示范
  • QCLOUD_IOT_MQTT_TX_BUF_LEN和QCLOUD_IOT_MQTT_RX_BUF_LEN:接收和发送缓冲区大小,根据业务需求来设置,最大不超过16K
  • MAX_RECONNECT_WAIT_INTERVAL:重连最大等待时间,需要快速重连的需要减小该值
  • MQTT_RMDUP_MSG_ENABLED和MQTT_MAX_REPEAT_BUF_LEN:这两个参数主要是用作消息过滤的,因为平台根据QOS1会实现重传,然而由于消息在链路中存在延时,所以需要对我们已经接受到的消息进行过滤,避免重复接收处理。一般建议打开,BUF长度根据实际应用设定,采用的是覆盖最旧的消息ID的策略