基於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接口都是非常簡單的,在後文會提及到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章