This directory contains two example programs demonstrating how to use an MQTT client from a C program:
- main.c - a simple command-line based publisher/subscriber written in C. The remainder of this document describes the details of this application.
- emqx_file_transfer.c - an example demonstrating how to use EMQX File Transfer Extension (https://www.emqx.io/docs/en/v5/file-transfer/introduction.html) from a C program. This example also works as a simple command line tool for using EMQX File Transfer Extension. Please see comments in the source code of this program for details. The compilation instruction in this document also works for this program.
This article mainly introduces how to use Eclipse Paho C
in the C project, and implement the connection, subscription, messaging, unsubscribing and other functions between the client and MQTT broker.
Eclipse Paho Embedded C can be used on the desktop operating system, but mainly for embedded environments such as mbed, Arduino and FreeRTOS .
sudo apt-get update
sudo apt-get -y install build-essential git cmake
The continuous integration builds can be found on Travis-CI for Linux and Mac, and AppVeyor for Windows.
git clone https://github.com/eclipse/paho.mqtt.c.git
cd org.eclipse.paho.mqtt.c.git
make
sudo make install
mkdir build.paho
cd build.paho
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
cmake -G "NMake Makefiles" -DPAHO_WITH_SSL=TRUE -DPAHO_BUILD_DOCUMENTATION=FALSE -DPAHO_BUILD_SAMPLES=TRUE -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=TRUE ..
nmake
This article will use the free public MQTT broker provided by EMQ X. This service was created based on the EMQ X Cloud. The information about broker access is as follows:
- Broker: broker.emqx.io
- TCP Port: 1883
- WebSocket Port: 8083
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "MQTTClient.h"
#define ADDRESS "tcp://broker.emqx.io:1883"
#define USERNAME "emqx"
#define PASSWORD "public"
#define CLIENTID "c-client"
#define QOS 0
#define TOPIC "emqx/c-test"
#define TIMEOUT 10000L
void publish(MQTTClient client, char *topic, char *payload) {
MQTTClient_message message = MQTTClient_message_initializer;
message.payload = payload;
message.payloadlen = strlen(payload);
message.qos = QOS;
message.retained = 0;
MQTTClient_deliveryToken token;
MQTTClient_publishMessage(client, topic, &message, &token);
MQTTClient_waitForCompletion(client, token, TIMEOUT);
printf("Send `%s` to topic `%s` \n", payload, TOPIC);
}
Define the on_message callback function to print the content of the messages received by the subscribed topic
int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
char *payload = message->payload;
printf("Received `%s` from `%s` topic \n", payload, topicName);
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
int rc;
MQTTClient client;
MQTTClient_create(&client, ADDRESS, CLIENTID, 0, NULL);
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
conn_opts.username = USERNAME;
conn_opts.password = PASSWORD;
MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to connect, return code %d\n", rc);
exit(-1);
} else {
printf("Connected to MQTT Broker!\n");
}
// subscribe topic
MQTTClient_subscribe(client, TOPIC, QOS);
char payload[16];
for (int i = 0; i < 100; i += 1) {
// publish message to broker
snprintf(payload, 16, "message-%d", i);
publish(client, TOPIC, payload);
sleep(1);
}
MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer;
/* Set the value of 'verify' to 0, which means that the domain should not be checked. Otherwise, if the domain does not match, an error will occur. */
ssl_opts.verify = 0;
ssl_opts.keyStore = CLIENTCERT;
ssl_opts.trustStore = CACERT;
ssl_opts.privateKey = PRIVATEKEY;
conn_opts.ssl = &ssl_opts;
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "MQTTClient.h"
#define ADDRESS "tcp://broker.emqx.io:1883"
#define USERNAME "emqx"
#define PASSWORD "public"
#define CLIENTID "c-client"
#define QOS 0
#define TOPIC "emqx/c-test"
#define TIMEOUT 10000L
void publish(MQTTClient client, char *topic, char *payload) {
MQTTClient_message message = MQTTClient_message_initializer;
message.payload = payload;
message.payloadlen = strlen(payload);
message.qos = QOS;
message.retained = 0;
MQTTClient_deliveryToken token;
MQTTClient_publishMessage(client, topic, &message, &token);
MQTTClient_waitForCompletion(client, token, TIMEOUT);
printf("Send `%s` to topic `%s` \n", payload, TOPIC);
}
int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
char *payload = message->payload;
printf("Received `%s` from `%s` topic \n", payload, topicName);
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
int main(int argc, char *argv[]) {
int rc;
MQTTClient client;
MQTTClient_create(&client, ADDRESS, CLIENTID, 0, NULL);
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
conn_opts.username = USERNAME;
conn_opts.password = PASSWORD;
MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to connect, return code %d\n", rc);
exit(-1);
} else {
printf("Connected to MQTT Broker!\n");
}
// subscribe topic
MQTTClient_subscribe(client, TOPIC, QOS);
char payload[16];
for (int i = 0; i < 100; i += 1) {
// publish message to broker
snprintf(payload, 16, "message-%d", i);
publish(client, TOPIC, payload);
sleep(1);
}
MQTTClient_disconnect(client, TIMEOUT);
MQTTClient_destroy(&client);
return rc;
}
- Write the CMakeLists.txt file
cmake_minimum_required(VERSION 3.17) find_package(eclipse-paho-mqtt-c 1.3.9 REQUIRED) project(mqtt_c C) include_directories(/usr/local/include) link_directories(/usr/local/lib) set(CMAKE_C_STANDARD 99) add_executable(mqtt_c main.c) target_link_libraries(mqtt_c paho-mqtt3c)
- Compile and run code