MQTT Client Drive 库的编译和使用(基于C语言)
MQTT Client Drive 库的编译和使用
运行环境:Windows 10 64位
、 Visual Stdio 2017 Community
一、Client Library
MQTT官网提供不同应用场景的Client库
博主选择下载C语言实现的Client Library:Eclipse Paho C
,GigHub地址:https://github.com/eclipse/paho.mqtt.c.git
1-1 编译MQTT的准备
安装包介绍:
🔶 OpenSSL,博主下载版本:Win64OpenSSL-1_1_1q.msi
工具介绍:
🔶 Git,博主下载版本:git version 2.34.1.windows.1
🔶 CmMke Gui,博主下载版本:cmake-3.16.2-win64-x64.msi
🔶 Visual Studio 2017 Community,下载地址:百度网盘下载链接: https://pan.baidu.com/s/1jJXyRMA
密码: ub6c
1-2 开始编译MQTT
💛 第一步
在paho.mqtt.c\
创建paho.mqtt.c\build
文件夹,用来存放Cmake输出的工程文件
🧡 第二步
选择编译项和补全OpenSSL路径
💚 第三步
进入paho.mqtt.c\build
文件夹,选择并打开Eclipse Paho C.sln
编译结果选择Release和x64
二、Client Publish
注意:需提前搭建mqtt server,搭建步骤参考--MQTT Server
❤ 第一步
Visual Studio 2017 创建项目工程MQTTC_Publish
,并在项目工程文件夹下创建Include
和Lib
文件夹。在Include
文件夹下创建paho.mqtt.c
文件夹
将从GitHub上下载的文件夹下的src复制到MQTT_Publish\Include\paho.mqtt.c\
下,将编译结果paho-mqtt3as-static.lib
复制到MQTT_Publish\Lib\
下
❤ 第二步
配置编译环境
❤ 第三步
将从GitHub上下载的文件夹下的src文件夹下的MQTTAsync_publish_time.c
内容复制到项目源文件内容,并做部分修改
/*******************************************************************************
* Copyright (c) 2012, 2020 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0/
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial contribution
* Frank Pagliughi - loop to repeatedly read and sent time values.
*******************************************************************************/
// This is a somewhat contrived example to show an application that publishes
// continuously, like a data acquisition app might do. In this case, though,
// we don't have a sensor to read, so we use the system time as the number
// of milliseconds since the epoch to simulate a data input.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "MQTTAsync.h"
#if !defined(_WIN32)
#include <unistd.h>
#else
#include <windows.h>
#include <Minwinbase.h>
#endif
#if defined(_WRS_KERNEL)
#include <OsWrapper.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
#define snprintf _snprintf
#endif
// Better not to flood a public broker. Test against localhost.
#define ADDRESS "tcp://10.8.198.55:1883"
#define CLIENTID "ExampleClientTimePub"
#define TOPIC "data/time"
#define QOS 1
#define TIMEOUT 10000L
#define SAMPLE_PERIOD 1000L // in ms
volatile int finished = 0;
volatile int connected = 0;
void connlost(void *context, char *cause)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
int rc;
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
printf("Reconnecting\n");
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
finished = 1;
}
}
void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
{
printf("Disconnect failed\n");
finished = 1;
}
void onDisconnect(void* context, MQTTAsync_successData* response)
{
printf("Successful disconnection\n");
finished = 1;
}
void onSendFailure(void* context, MQTTAsync_failureData* response)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
int rc;
printf("Message send failed token %d error code %d\n", response->token, response->code);
opts.onSuccess = onDisconnect;
opts.onFailure = onDisconnectFailure;
opts.context = client;
if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start disconnect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
}
void onSend(void* context, MQTTAsync_successData* response)
{
// This gets called when a message is acknowledged successfully.
}
void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
printf("Connect failed, rc %d\n", response ? response->code : 0);
finished = 1;
}
void onConnect(void* context, MQTTAsync_successData* response)
{
printf("Successful connection\n");
connected = 1;
}
int messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* m)
{
/* not expecting any messages */
return 1;
}
int64_t getTime(void)
{
#if defined(_WIN32)
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return ((((int64_t)ft.dwHighDateTime) << 8) + ft.dwLowDateTime) / 10000;
#else
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ((int64_t)ts.tv_sec * 1000) + ((int64_t)ts.tv_nsec / 1000000);
#endif
}
int main(int argc, char* argv[])
{
MQTTAsync client;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
MQTTAsync_responseOptions pub_opts = MQTTAsync_responseOptions_initializer;
int rc;
if ((rc = MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTASYNC_SUCCESS)
{
printf("Failed to create client object, return code %d\n", rc);
exit(EXIT_FAILURE);
}
if ((rc = MQTTAsync_setCallbacks(client, NULL, connlost, messageArrived, NULL)) != MQTTASYNC_SUCCESS)
{
printf("Failed to set callback, return code %d\n", rc);
exit(EXIT_FAILURE);
}
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = onConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = client;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
while (!connected) {
#if defined(_WIN32)
Sleep(100);
#else
usleep(100000L);
#endif
}
long long count = 0;
while (!finished) {
//int64_t t = getTime();
time_t t;
struct tm * lt;
time(&t);
lt = localtime(&t);
char time_txt[256] = {0};
// printf("%d-%d-%d %d:%d:%d\n", lt->tm_year + 1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
sprintf(time_txt, "%d-%d-%d %d:%d:%d", lt->tm_year + 1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec);
char buf[256];
//strcpy(buf, time_txt);
sprintf(buf, "%s...%lld", time_txt, count++);
//int n = snprintf(buf, sizeof(buf), "%lld", (long long)t);
int n = strlen(buf);
printf("%s\n", buf);
pub_opts.onSuccess = onSend;
pub_opts.onFailure = onSendFailure;
pub_opts.context = client;
pubmsg.payload = buf;
pubmsg.payloadlen = n;
pubmsg.qos = QOS;
pubmsg.retained = 1;
if ((rc = MQTTAsync_sendMessage(client, TOPIC, &pubmsg, &pub_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start sendMessage, return code %d\n", rc);
exit(EXIT_FAILURE);
}
#if defined(_WIN32)
Sleep(SAMPLE_PERIOD);
#else
usleep(SAMPLE_PERIOD * 1000);
#endif
}
MQTTAsync_destroy(&client);
return rc;
}
❤ 第四步
编译结果
三、Client Subscribe
第一步和第二步与Client Publish一样
❤ 第三步
将从GitHub上下载的文件夹下的src文件夹下的MQTTAsync_subscribe.c
内容复制到项目源文件内容
/*******************************************************************************
* Copyright (c) 2012, 2022 IBM Corp., Ian Craggs
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* https://www.eclipse.org/legal/epl-2.0/
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial contribution
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTAsync.h"
#if !defined(_WIN32)
#include <unistd.h>
#else
#include <windows.h>
#endif
#if defined(_WRS_KERNEL)
#include <OsWrapper.h>
#endif
#define ADDRESS "tcp://mqtt.eclipseprojects.io:1883"
#define CLIENTID "ExampleClientSub"
#define TOPIC "MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
int disc_finished = 0;
int subscribed = 0;
int finished = 0;
void onConnect(void* context, MQTTAsync_successData* response);
void onConnectFailure(void* context, MQTTAsync_failureData* response);
void connlost(void *context, char *cause)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
int rc;
printf("\nConnection lost\n");
if (cause)
printf(" cause: %s\n", cause);
printf("Reconnecting\n");
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = onConnect;
conn_opts.onFailure = onConnectFailure;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
finished = 1;
}
}
int msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message)
{
printf("Message arrived\n");
printf(" topic: %s\n", topicName);
printf(" message: %.*s\n", message->payloadlen, (char*)message->payload);
MQTTAsync_freeMessage(&message);
MQTTAsync_free(topicName);
return 1;
}
void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
{
printf("Disconnect failed, rc %d\n", response->code);
disc_finished = 1;
}
void onDisconnect(void* context, MQTTAsync_successData* response)
{
printf("Successful disconnection\n");
disc_finished = 1;
}
void onSubscribe(void* context, MQTTAsync_successData* response)
{
printf("Subscribe succeeded\n");
subscribed = 1;
}
void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
{
printf("Subscribe failed, rc %d\n", response->code);
finished = 1;
}
void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
printf("Connect failed, rc %d\n", response->code);
finished = 1;
}
void onConnect(void* context, MQTTAsync_successData* response)
{
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
int rc;
printf("Successful connection\n");
printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
opts.onSuccess = onSubscribe;
opts.onFailure = onSubscribeFailure;
opts.context = client;
if ((rc = MQTTAsync_subscribe(client, TOPIC, QOS, &opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start subscribe, return code %d\n", rc);
finished = 1;
}
}
int main(int argc, char* argv[])
{
MQTTAsync client;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer;
int rc;
int ch;
if ((rc = MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL))
!= MQTTASYNC_SUCCESS)
{
printf("Failed to create client, return code %d\n", rc);
rc = EXIT_FAILURE;
goto exit;
}
if ((rc = MQTTAsync_setCallbacks(client, client, connlost, msgarrvd, NULL)) != MQTTASYNC_SUCCESS)
{
printf("Failed to set callbacks, return code %d\n", rc);
rc = EXIT_FAILURE;
goto destroy_exit;
}
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.onSuccess = onConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = client;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start connect, return code %d\n", rc);
rc = EXIT_FAILURE;
goto destroy_exit;
}
while (!subscribed && !finished)
#if defined(_WIN32)
Sleep(100);
#else
usleep(10000L);
#endif
if (finished)
goto exit;
do
{
ch = getchar();
} while (ch!='Q' && ch != 'q');
disc_opts.onSuccess = onDisconnect;
disc_opts.onFailure = onDisconnectFailure;
if ((rc = MQTTAsync_disconnect(client, &disc_opts)) != MQTTASYNC_SUCCESS)
{
printf("Failed to start disconnect, return code %d\n", rc);
rc = EXIT_FAILURE;
goto destroy_exit;
}
while (!disc_finished)
{
#if defined(_WIN32)
Sleep(100);
#else
usleep(10000L);
#endif
}
destroy_exit:
MQTTAsync_destroy(&client);
exit:
return rc;
}
❤ 第四步
编译结果
四、多语言编译版本
Eclipse 官网提供已经编译好的多语言库,无需用户编译,下载直接使用。
资源地址:Eclipse Paho
五、参考来源
win10中使用VS2017\VS2019编译MQTT(包含32位、64位;Debug版本\Release版本)(附示例demo)