CloudAMQP with MQTT and C
We recommend the Eclipse Paho C client.
The examples use its synchronous MQTTClient API. On Debian and Ubuntu,
install it with:
sudo apt-get install libpaho-mqtt-dev
Publish and subscribe
Set MQTT_HOST, MQTT_PORT, MQTT_USERNAME and MQTT_PASSWORD to the MQTT
details on your instance’s details page in the CloudAMQP console. Port 8883
uses TLS. Without them, the examples connect to a local broker.
Save the publisher as publisher.c:
#include <MQTTClient.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const char* env(const char* name, const char* fallback) {
const char* value = getenv(name);
return value ? value : fallback;
}
int main(void) {
const char* port = env("MQTT_PORT", "1883");
int tls = strcmp(port, "8883") == 0;
char uri[256];
snprintf(uri, sizeof uri, "%s://%s:%s", tls ? "ssl" : "tcp", env("MQTT_HOST", "localhost"), port);
char client_id[32];
snprintf(client_id, sizeof client_id, "publisher-%d", (int)getpid());
MQTTClient client;
MQTTClient_create(&client, uri, client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL);
MQTTClient_connectOptions options = MQTTClient_connectOptions_initializer;
options.username = env("MQTT_USERNAME", "guest");
options.password = env("MQTT_PASSWORD", "guest");
MQTTClient_SSLOptions ssl = MQTTClient_SSLOptions_initializer;
ssl.verify = 1; // Paho C checks the certificate, but not its hostname, by default
if (tls) options.ssl = &ssl;
int rc = MQTTClient_connect(client, &options);
if (rc != MQTTCLIENT_SUCCESS) {
fprintf(stderr, "Connection failed: %s\n", MQTTClient_strerror(rc));
return 1;
}
// QoS 1, and waitForCompletion waits for the broker's PUBACK
const char* message = "Hello world!";
MQTTClient_deliveryToken token;
MQTTClient_publish(client, "hello", (int)strlen(message), message, 1, 0, &token);
rc = MQTTClient_waitForCompletion(client, token, 10000);
if (rc != MQTTCLIENT_SUCCESS) {
fprintf(stderr, "Publish failed: %s\n", MQTTClient_strerror(rc));
return 1;
}
printf(" [x] Sent '%s'\n", message);
MQTTClient_disconnect(client, 1000);
MQTTClient_destroy(&client);
return 0;
}
Save the subscriber as worker.c:
#include <MQTTClient.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const char* env(const char* name, const char* fallback) {
const char* value = getenv(name);
return value ? value : fallback;
}
int main(void) {
// Print each line straight away, also when the output isn't a terminal
setvbuf(stdout, NULL, _IOLBF, 0);
const char* port = env("MQTT_PORT", "1883");
int tls = strcmp(port, "8883") == 0;
char uri[256];
snprintf(uri, sizeof uri, "%s://%s:%s", tls ? "ssl" : "tcp", env("MQTT_HOST", "localhost"), port);
char client_id[32];
snprintf(client_id, sizeof client_id, "worker-%d", (int)getpid());
MQTTClient client;
MQTTClient_create(&client, uri, client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL);
MQTTClient_connectOptions options = MQTTClient_connectOptions_initializer;
options.username = env("MQTT_USERNAME", "guest");
options.password = env("MQTT_PASSWORD", "guest");
MQTTClient_SSLOptions ssl = MQTTClient_SSLOptions_initializer;
ssl.verify = 1; // Paho C checks the certificate, but not its hostname, by default
if (tls) options.ssl = &ssl;
int rc = MQTTClient_connect(client, &options);
if (rc != MQTTCLIENT_SUCCESS) {
fprintf(stderr, "Connection failed: %s\n", MQTTClient_strerror(rc));
return 1;
}
MQTTClient_subscribe(client, "hello", 1);
printf(" [*] Waiting for messages. To exit press CTRL+C\n");
// Paho C acks each QoS 1 message as it arrives
for (;;) {
char* topic;
int topic_length;
MQTTClient_message* message;
rc = MQTTClient_receive(client, &topic, &topic_length, &message, 1000);
if (rc != MQTTCLIENT_SUCCESS) {
fprintf(stderr, "Connection lost: %s\n", MQTTClient_strerror(rc));
return 1;
}
if (message) {
printf(" [x] Received '%.*s'\n", message->payloadlen, (char*)message->payload);
MQTTClient_freeMessage(&message);
MQTTClient_free(topic);
}
}
}
Build both with cc -o publisher publisher.c -lpaho-mqtt3cs and
cc -o worker worker.c -lpaho-mqtt3cs, then run ./worker in one terminal and
./publisher in another.
A runnable example is in c/paho-mqtt in cloudamqp/examples.
Good to know
- Put the vhost in the username, as
vhost:user. MQTT has no vhost of its own, and the console shows the username that way. - Link with
paho-mqtt3cs, the synchronous library with TLS. - Set
verify = 1in the SSL options. Paho C checks the server certificate against the system’s certificates, but by default not that it matches the hostname. - Use QoS 1, so
MQTTClient_waitForCompletionwaits for the broker’s PUBACK. Paho C acks each incoming QoS 1 message as it arrives. - Paho C doesn’t reconnect with the synchronous API. When
MQTTClient_receivefails, connect and subscribe again.