基于Socket的跨平台MQTT客户端 省资源、高稳定

kawaii-mqtt软件包是一个基于socket API之上的跨平台MQTT客户端

 

基于socket API的MQTT客户端,拥有非常简洁的API接口,以极少的资源实现QOS2的服务质量,并且无缝衔接了mbedtls加密库。此仓库是专门为RT-Thread做的软件包,原始仓库位于:

https://github.com/jiejieTop/mqttclient

* 以上链接请复制至外部浏览器打开

名字的由来

kawaii 是“卡哇伊”的谐音,单词的原意也是可爱的意思,一个很可爱的程序员制作的可爱的软件包 ღ( ´・ᴗ・` )~

使用本软件包有哪些优势?

1

基于标准BSD socket之上开发,只要是兼容BSD socket的系统均可使用。

2

稳定:无论是掉线重连,丢包重发,都是严格遵循MQTT协议标准执行,除此之外对大数据量的测试无论是收是发,都是非常稳定(一次发送135K数据,3秒一次),高频测试也是非常稳定(7个主题同时收发,每秒一次,也就是1秒14个mqtt报文,服务质量QoS0、QoS1、QoS2都有)。因为作者以极少的资源设计了记录机制,对采用QoS1服务质量的报文必须保证到达一次,当发布的主题(qos1、qos2都适用)没有被服务器收到时会自动重发,而对QoS2服务质量的报文保证有且只有处理一次(如果不相信它稳定性的同学可以自己去修改源码,专门为QoS2服务质量去做测试,故意不回复PUBREC包,让服务器重发QoS2报文,且看看客户端是否有且只有处理一次),而对于掉线重连的稳定性,这种则是基本操作了,没啥好说的,在自动重连后还会自动重新订阅主题,保证主题不会丢失,因此在测试中稳定性极好。

3

轻量级:整个代码工程极其简单,不使用mbedtls情况下,占用资源极少,作者曾使用esp8266模组与云端通信,整个工程代码消耗的RAM不足15k(包括系统占用的开销,对数据的处理开销,而此次还是未优化的情况下,还依旧完美保留了掉线重连的稳定性,但是对应qos1、qos2服务质量的报文则未做测试,因为STM32F103C8T6芯片资源实在是太少了,折腾不起)。

4

无缝衔接mbedtls加密传输,让网络传输更加安全,而且接口层完全不需要用户理会,无论是否加密,kawaii-mqtt对用户提供的API接口是没有变化的,这就很好的兼容了一套代应用层的码可以加密传输也可以不加密传输。

5

拥有极简的API接口,总的来说,kawaii-mqtt的配置都有默认值,基本无需配置都能使用的,也可以随意配置,对配置都有健壮性检测,这样子设计的API接口也是非常简单。

6

有非常好的代码风格与思想:整个代码采用分层式设计,代码实现采用异步处理的思想,降低耦合,提高性能,具体体现在什么地方呢?很简单,目前市面上很多MQTT客户端发布主题都是要阻塞等待ack,这是非常暴力的行为,阻塞当前线程等待服务器的应答,那如果我想要发送数据怎么办,或者我要重复检测数据怎么办,你可能会说,指定阻塞时间等待,那如果网络延迟,ack迟迟不来,我就白等了吗,对于qos1、qos2的服务质量怎么办,所以说这种还是要异步处理的思想,我发布主题,那我发布出去就好了,不需要等待,对于qos1、qos2服务质量的MQTT报文,如果服务器没收到,那我重发就可以,这种重发也是异步的处理,完全不会阻塞当前线程。

7

MQTT协议支持主题通配符“#”、“+”。

8

订阅的主题与消息处理完全分离,让编程逻辑更加简单易用,用户无需理会错综复杂的逻辑关系。

9

kawaii-mqtt内部已实现保活处理机制,无需用户过多关心理会,用户只需专心处理应用功能即可。

10

无缝衔接salof:它是一个同步异步日志输出框架,在空闲时候输出对应的日志信息,也可以将信息写入flash中保存,方便调试。

11

不对外产生依赖。

整体框架

拥有非常明确的分层框架

API

kawaii-mqtt拥有非常简洁的api接口,并且api见名知其义,非常易于使用。

 1int mqtt_init(mqtt_client_t* c, client_init_params_t* init);
 2int mqtt_release(mqtt_client_t* c);
 3int mqtt_connect(mqtt_client_t* c);
 4int mqtt_disconnect(mqtt_client_t* c);
 5int mqtt_subscribe(mqtt_client_t* c, const char* topic_filter, mqtt_qos_t qos, message_handler_t msg_handler);
 6int mqtt_unsubscribe(mqtt_client_t* c, const char* topic_filter);
 7int mqtt_publish(mqtt_client_t* c, const char* topic_filter, mqtt_message_t* msg);
 8
 9int mqtt_keep_alive(mqtt_client_t* c);
10int mqtt_yield(mqtt_client_t* c, int timeout_ms);

核心

mqtt_client_t 是核心结构

 1typedef struct mqtt_client {
 2    unsigned short              packet_id;
 3    unsigned char               ping_outstanding;
 4    unsigned char               ack_handler_number;
 5    unsigned char               *read_buf;
 6    unsigned char               *write_buf;
 7    unsigned int                cmd_timeout;
 8    unsigned int                read_buf_size;
 9    unsigned int                write_buf_size;
10    unsigned int                reconnect_try_duration;
11    void                        *reconnect_date;
12    reconnect_handler_t         reconnect_handler;
13    client_state_t              client_state;
14    platform_mutex_t            write_lock;
15    platform_mutex_t            global_lock;
16    list_t                      msg_handler_list;
17    list_t                      ack_handler_list;
18    network_t                   *network;
19    platform_thread_t           *thread;
20    platform_timer_t            reconnect_timer;
21    platform_timer_t            last_sent;
22    platform_timer_t            last_received;
23    connect_params_t            *connect_params;
24} mqtt_client_t;

该结构主要维护以下内容:

1、读写数据缓冲区read_buf、write_buf

2、命令超时时间cmd_timeout(主要是读写阻塞时间、等待响应的时间、重连等待时间)

3、维护ack链表ack_handler_list,这是异步实现的核心,所有等待响应的报文都会被挂载到这个链表上

4、维护消息处理列表msg_handler_list,这是mqtt协议必须实现的内容,所有来自服务器的publish报文都会被处理(前提是订阅了对应的消息)

5、维护一个网卡接口network

6、维护一个内部线程thread,所有来自服务器的mqtt包都会在这里被处理!

7、两个定时器,分别是掉线重连定时器与保活定时器reconnect_timer、last_sent、last_received

8、一些连接的参数connect_params

初始化

主要是配置mqtt_client_t结构的相关信息,如果没有指定初始化参数,则系统会提供默认的参数。但连接部分的参数则必须指定:

1 init_params.connect_params.network_params.addr = "[你的mqtt服务器IP地址或者是域名]";
2    init_params.connect_params.network_params.port = "1883";    //端口号
3    init_params.connect_params.user_name = "jiejietop";
4    init_params.connect_params.password = "123456";
5    init_params.connect_params.client_id = "clientid";
6
7    mqtt_init(&client, &init_params);

连接服务器

1    mqtt_connect(&client);

订阅报文

参数只有 mqtt_client_t 类型的指针,字符串类型的主题(支持通配符"#" "+"),主题的服务质量,以及收到报文的处理函数,如不指定则有默认处理函数。

1   mqtt_subscribe(&client, "testtopic0", QOS0, topic_test1_handler);
2    mqtt_subscribe(&client, "testtopic1", QOS1, NULL);
3    mqtt_subscribe(&client, "testtopic2", QOS2, NULL);

发布报文

参数只有 mqtt_client_t 类型的指针,字符串类型的主题(支持通配符),要发布的消息(包括服务质量消息主体)。

1   mqtt_message_t msg;
2
3    msg.qos = 2;
4    msg.payload = (void *) buf;
5
6    mqtt_publish(&client, "testtopic1", &msg);

其他的API接口都是非常简单的,在后文会提及到。

发布了189 篇原创文章 · 获赞 86 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/aa120515692/article/details/104670311