Paho C を使ったデプロイメントへの接続
この記事では、Cプロジェクトで Eclipse Paho C
を使用し、クライアントと MQTT ブローカー間の接続、サブスクライブ、メッセージ送受信、サブスクライブ解除などの機能を実装する方法を主に紹介します。
Eclipse Paho Embedded C はデスクトップOSでも使用可能ですが、主に mbed、Arduino、FreeRTOS などの組み込み環境向けです。
前提条件
MQTT ブローカーのデプロイ
- EMQX が提供する無料のパブリック MQTT ブローカーを利用できます。このサービスはEMQX プラットフォームをベースに作成されています。ブローカーの接続情報は以下の通りです:
- ブローカー: broker.emqx.io
- TCP ポート: 1883
- TLS/SSL ポート: 8883
- また、デプロイメントを作成することも可能です。デプロイメントの概要で接続情報を確認してください。デプロイメントが稼働していることを確認してください。同時に、WebSocket を使って MQTT サーバーへの接続テストも可能です。独自にデプロイメントを作成する場合は、アクセス制御 -> 認証を確認し、検証用のユーザー名とパスワードを設定してください。
インストール依存関係
sudo apt-get update
sudo apt-get -y install build-essential git cmake
ソースからのビルド
継続的インテグレーションビルドは、Linux と Mac は Travis-CI、Windows は AppVeyor で公開されています。
Linux/Mac
git clone https://github.com/eclipse/paho.mqtt.c.git
cd org.eclipse.paho.mqtt.c.git
make
sudo make install
Windows
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
TCP プロトコルでの接続
このセクションでは、TCP ポートを介して MQTT ブローカーに接続する方法を紹介します。
依存ライブラリのインクルード
c#include "stdlib.h" #include "string.h" #include "unistd.h" #include "MQTTClient.h"
接続先アドレス、認証情報、メッセージのパブリッシュおよび受信トピックの定義
c// SSL/TLS 接続を有効化(1: SSL/TLS、0: TCP) #define USE_SSL 0 #if USE_SSL #define ADDRESS "ssl://broker.emqx.io:8883" #else #define ADDRESS "tcp://broker.emqx.io:1883" #endif #define USERNAME "emqx" #define PASSWORD "public" #define CLIENTID "c-client" #define QOS 0 #define TOPIC "emqx/c-test" #define TIMEOUT 10000L
ブローカーへの接続
cint 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; if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("接続に失敗しました。戻りコード %d\n", rc); exit(-1); } else { printf("MQTT ブローカーに接続しました!\n"); }
SSL/TLS プロトコルでの接続
このセクションでは、SSL/TLS ポートを介して MQTT ブローカーに接続する方法を紹介します。
接続先アドレスを定義し、
USE_SSL
を 1 に設定します。c// SSL/TLS 接続を有効化(1: SSL/TLS、0: TCP) #define USE_SSL 1
SSL/TLS でブローカーに接続
configureSSLOptions()
関数で SSL オプションを設定します。サーバー証明書を設定する必要がある場合は、ssl_opts.trustStore
に証明書をロードしてください。不要な場合はssl_opts.enableServerCertAuth
を 0 に設定します。cMQTTClient_SSLOptions configureSSLOptions() { MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer; ssl_opts.enableServerCertAuth = 1; // CA_CERTIFICATE_FILE_Path にサーバー CA 証明書を指定 // ssl_opts.trustStore = CA_CERTIFICATE_FILE_Path; return ssl_opts; } ··· #if USE_SSL MQTTClient_SSLOptions ssl_opts = configureSSLOptions(); conn_opts.ssl = &ssl_opts; #endif
パブリッシュとサブスクライブ
このセクションでは、MQTT ブローカーへの接続に成功した後の、トピックのサブスクライブとメッセージのパブリッシュ方法を紹介します。
トピックのサブスクライブ
サブスクライブするトピックとそのQoSレベルを設定します。
// トピックをサブスクライブ
MQTTClient_subscribe(client, TOPIC, QOS);
トピックのサブスクライブ解除
以下のコードでトピックのサブスクライブを解除できます。解除するトピックを定義してください。
MQTTClient_unsubscribe(client, TOPIC);
メッセージのパブリッシュ
メッセージをパブリッシュする際には、ブローカーにトピックとペイロードを通知します。
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("トピック `%s` に `%s` を送信しました\n", TOPIC, payload);
}
// メッセージのパブリッシュを完了するために `publish` 関数をループで呼び出す
char payload[16];
for (int i = 0; i < 100; i += 1) {
// ブローカーにメッセージをパブリッシュ
snprintf(payload, 16, "message-%d", i);
publish(client, TOPIC, payload);
sleep(1);
}
メッセージの受信
以下のコードは、クライアントがメッセージイベントを監視し、メッセージ受信後にコールバック関数を実行して、受信したメッセージとトピックをコンソールに表示します。
MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);
···
// on_message コールバック関数を定義し、サブスクライブしたトピックで受信したメッセージの内容を表示
int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
char *payload = message->payload;
printf("トピック `%s` から `%s` を受信しました\n", topicName, payload);
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
MQTT ブローカーからの切断
クライアントが能動的に切断する場合は、以下のコードを使用します。
MQTTClient_disconnect(client, TIMEOUT);
MQTTClient_destroy(&client);
上記は主要なコードのみを記載しています。プロジェクトの完全なコードは mqtt-client-C-paho にありますので、ダウンロードしてお試しください。
完全なコード例
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "MQTTClient.h"
// SSL/TLS 接続を有効化(1: SSL/TLS、0: TCP)
#define USE_SSL 1
#if USE_SSL
#define ADDRESS "ssl://broker.emqx.io:8883"
#else
#define ADDRESS "tcp://broker.emqx.io:1883"
#endif
#define USERNAME "emqx"
#define PASSWORD "public"
#define CLIENTID "c-client"
#define QOS 0
#define TOPIC "emqx/c-test"
#define TIMEOUT 10000L
MQTTClient_SSLOptions configureSSLOptions() {
MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer;
ssl_opts.enableServerCertAuth = 1;
ssl_opts.trustStore = CA_CERTIFICATE_FILE;
return ssl_opts;
}
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("トピック `%s` に `%s` を送信しました\n", TOPIC, payload);
}
int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
char *payload = message->payload;
printf("トピック `%s` から `%s` を受信しました\n", topicName, payload);
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;
#if USE_SSL
MQTTClient_SSLOptions ssl_opts = configureSSLOptions();
conn_opts.ssl = &ssl_opts;
#endif
MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("接続に失敗しました。戻りコード %d\n", rc);
exit(-1);
} else {
printf("MQTT ブローカーに接続しました!\n");
}
// トピックをサブスクライブ
MQTTClient_subscribe(client, TOPIC, QOS);
char payload[16];
for (int i = 0; i < 10; i += 1) {
// ブローカーにメッセージをパブリッシュ
snprintf(payload, 16, "message-%d", i);
publish(client, TOPIC, payload);
sleep(1);
}
MQTTClient_unsubscribe(client, TOPIC);
MQTTClient_disconnect(client, TIMEOUT);
MQTTClient_destroy(&client);
return rc;
}
テスト
CMakeLists.txt ファイルを作成
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)
コードをコンパイルして実行
まとめ
本記事では、Cプロジェクトで MQTT 接続の作成、サブスクライブ、メッセージの送受信、サブスクライブ解除、切断を実装しました。サンプルのソースコードはこちらからダウンロード可能です。また、他言語のデモ例もGitHubで多数公開されています。