MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是IBM開發的一個即時通信協議,經過MQTT協議,目前已經擴展出了數十個MQTT服務器端程序,能夠經過PHP,JAVA,Python,C,C#等系統語言來向MQTT發送相關消息。隨着移動互聯網的發展,MQTT因爲開放源代碼,耗電量小等特色,將會在移動消息推送領域會有更多的貢獻,在物聯網領域,傳感器與服務器的通訊,信息的收集,MQTT均可以做爲考慮的方案之一。在將來MQTT會進入到咱們生活的各各方面。The Paho MQTT C Client is a fully fledged MQTT client written in ANSI standard C. It avoids C++ in order to be as portable as possible. A C++ layer over this library is also available in Paho.git
目錄:github
MQTT主要用於服務端對客戶端進行消息推送,根據這個具體要求,很容易知道它包括兩個部分:客戶端、服務端。編程
MQTT消息推送是基於主題topic
模式的,能夠分開來講:服務器
MQTT協議是爲大量計算能力有限,且工做在低帶寬、不可靠的網絡的遠程傳感器和控制設備通信而設計的協議,它具備如下主要的幾項特性:markdown
在開始開發以前須要作一些準備工做,MQTT已經把全部的APIs封裝好了,咱們可使用它的dll庫,也能夠直接導入源碼進行混合編程,通常要求不高的話(由於不太懂得話,最好不要修改源碼)能夠直接將源碼生成dll,而後使用便可,下文就是使用該方式:網絡
git clone https://github.com/eclipse/paho.mqtt.c.gitsession
從這裏得到C Client源碼以後,能夠直接使用VS打開(我是VS2013):eclipse
對於上圖的說明,下載源碼後,打開將是以上界面,包括十來個工程,這裏講解幾個:異步
這裏根據自身的須要選擇不一樣的項目生成DLL便可,右擊單個項目->生成。因爲你電腦中可能沒有OPenSSL環境,若是點擊VS工具欄中的生成解決方案,十有八九會失敗,由於它會生成全部項目的解決方案,其實你根本用不着這麼多。async
另外,上圖中沒法打開包括文件VersionInfo.h
,你只須要在src文件夾中找到VersionInfo.h.in文件,去掉.in後綴->從新生成便可。
瞭解更多能夠閱讀《MQTT C Client for Posix and Windows》一文,下面根據官網資料,摘錄了幾個C語言實現MQTT的小DEMO。
MQTT使用起來也十分容易,基本上就那四五個函數:MQTTClient_create(建立客戶端)、MQTTClient_connect(鏈接服務端)、MQTTClient_publishMessage(客戶端->服務端發送消息)、MQTTClient_subscribe(客戶端訂閱某個主題)等等。其中,不少異步回調函數,須要本身去實現,如,
MQTTAsync_setCallbacks(mqtt->_client, mqtt->_client, connlost, msgarrvd, NULL);
MQTTAsync_setCallbacks中,
另外,就是一些函數執行是否成功的回調函數,C語言封裝回調以後,就是這麼寫法,看起來有些變扭。有興趣的能夠看《淺談C/C++回調函數(Callback)& 函數指針》文章,再瞭解如下回調函數。
mqtt->_conn_opts.onSuccess = onConnect; mqtt->_conn_opts.onFailure = onConnectFailure;
最後,不得不說的就是,MQTT有些發送或者是訂閱的內容時(某些函數中),在編程最好將參數中傳進來的值在內存中拷貝一份再操做,筆者當時開發時,就是由於這樣的問題,折騰了較長時間,後來在wireshark中發現數據包中根本沒有內容,才知道是因爲函數參數是指針形式,直接在異步中使用可能會發生一些未知的錯誤。
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "MQTTClient.h" #define ADDRESS "tcp://localhost:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" #define QOS 1 #define TIMEOUT 10000L int main(int argc, char* argv[]) { MQTTClient client; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; MQTTClient_message pubmsg = MQTTClient_message_initializer; MQTTClient_deliveryToken token; int rc; MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("Failed to connect, return code %d\n", rc); exit(EXIT_FAILURE); } pubmsg.payload = PAYLOAD; pubmsg.payloadlen = strlen(PAYLOAD); pubmsg.qos = QOS; pubmsg.retained = 0; MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token); printf("Waiting for up to %d seconds for publication of %s\n" "on topic %s for client with ClientID: %s\n", (int)(TIMEOUT/1000), PAYLOAD, TOPIC, CLIENTID); rc = MQTTClient_waitForCompletion(client, token, TIMEOUT); printf("Message with delivery token %d delivered\n", token); MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); return rc; }
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "MQTTClient.h" #define ADDRESS "tcp://localhost:1883" #define CLIENTID "ExampleClientPub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" #define QOS 1 #define TIMEOUT 10000L volatile MQTTClient_deliveryToken deliveredtoken; void delivered(void *context, MQTTClient_deliveryToken dt) { printf("Message with token value %d delivery confirmed\n", dt); deliveredtoken = dt; } int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) { int i; char* payloadptr; printf("Message arrived\n"); printf(" topic: %s\n", topicName); printf(" message: "); payloadptr = message->payload; for(i=0; i<message->payloadlen; i++) { putchar(*payloadptr++); } putchar('\n'); MQTTClient_freeMessage(&message); MQTTClient_free(topicName); return 1; } void connlost(void *context, char *cause) { printf("\nConnection lost\n"); printf(" cause: %s\n", cause); } int main(int argc, char* argv[]) { MQTTClient client; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; MQTTClient_message pubmsg = MQTTClient_message_initializer; MQTTClient_deliveryToken token; int rc; MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered); if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("Failed to connect, return code %d\n", rc); exit(EXIT_FAILURE); } pubmsg.payload = PAYLOAD; pubmsg.payloadlen = strlen(PAYLOAD); pubmsg.qos = QOS; pubmsg.retained = 0; deliveredtoken = 0; MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token); printf("Waiting for publication of %s\n" "on topic %s for client with ClientID: %s\n", PAYLOAD, TOPIC, CLIENTID); while(deliveredtoken != token); MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); return rc; }
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "MQTTClient.h" #define ADDRESS "tcp://localhost:1883" #define CLIENTID "ExampleClientSub" #define TOPIC "MQTT Examples" #define PAYLOAD "Hello World!" #define QOS 1 #define TIMEOUT 10000L volatile MQTTClient_deliveryToken deliveredtoken; void delivered(void *context, MQTTClient_deliveryToken dt) { printf("Message with token value %d delivery confirmed\n", dt); deliveredtoken = dt; } int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) { int i; char* payloadptr; printf("Message arrived\n"); printf(" topic: %s\n", topicName); printf(" message: "); payloadptr = message->payload; for(i=0; i<message->payloadlen; i++) { putchar(*payloadptr++); } putchar('\n'); MQTTClient_freeMessage(&message); MQTTClient_free(topicName); return 1; } void connlost(void *context, char *cause) { printf("\nConnection lost\n"); printf(" cause: %s\n", cause); } int main(int argc, char* argv[]) { MQTTClient client; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; int rc; int ch; MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered); if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("Failed to connect, return code %d\n", rc); exit(EXIT_FAILURE); } printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n" "Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS); MQTTClient_subscribe(client, TOPIC, QOS); do { ch = getchar(); } while(ch!='Q' && ch != 'q'); MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); return rc; }