Shujima Blog

Apple製品,技術系の話をするブログ

Raspberry Pi同士でインターネット双方向通信【CloudMQTT】(#5 C言語Mosquitto受信編)

f:id:masa_flyu:20190216134218p:plain

各記事リンク

  1. 説明編
  2. Broker準備編
  3. Node-RED編
  4. C言語Mosquitto送信編
  5. C言語Mosquitto受信編(本記事です)

本編へ

以前の記事からの続きで,前回までに用意・確認したCloudMQTT環境を使います.

これについては以前の記事を参照してください.

環境

  • Raspberry Pi 3 Model B (2台)
  • Raspbian stretch 9.4
  • Ethernetでそれぞれインターネットに接続
  • Mosquittoライブラリ(以前の記事でインストールを行ってください)

受信プログラム

受信側のRaspberry Piで以下のCプログラムを作成してください.

ファイル名はなんでも構いませんが,私は「MQTTsub.c」としました.

Cファイル

#include <stdio.h>
#include <stdlib.h>
#include <string.h> //strlen();
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //strlen();
#include <unistd.h> //sleep();
#include <signal.h> //signal();

//mosquittoライブラリが必要です
//$ sudo apt-get install software-properties-common
//$ sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
//$ sudo apt-get install libmosquitto-dev
#include <mosquitto.h>

void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg);
void endCatch(int);

struct mosquitto *mosq;

int main()
{
    //↓↓↓ここからを編集する↓↓↓

    //MQTT Brokerの設定 (CloudMQTT)
    const char *ip = "ほげほげ.cloudmqtt.com"; //サーバのIPアドレスまたはドメイン名
    const int port = 54321; //サーバのポート番号
    const char *username = "username"; //サーバのユーザネーム
    const char *password = "password"; //サーバのパスワード

    //MQTTの設定
    const char *id = "RasPi2"; //発信者ごとに変える
    const char *topic = "topic1/sub1"; //送信するデータを区別するためのもの(受信側と統一する)

    //↑↑↑ここまでを編集する↑↑↑

    //Ctrl + Cなどによって強制終了するときに、終了時用の処理を呼び出す設定
    signal(SIGINT , endCatch );

    printf( "Prepareing mosquitto...\n" );
    //mosquittoの最初に呼び出す初期化関数
    mosquitto_lib_init();
    //mosquitto実態の作成
    mosq = mosquitto_new(id, 0, NULL);
    //失敗してたら
    if(!mosq)
    {
        perror( "Failed to create mosquitto\n" );
        mosquitto_lib_cleanup();
        return -1;
    }

    //ユーザ名、パスワードを教える
    mosquitto_username_pw_set(mosq, username, password);
    //受信した時に自動で呼び出す関数を指定する
    mosquitto_message_callback_set( mosq, on_message );

    //サーバーに接続する
    mosquitto_connect(mosq, ip, port, 60);
    printf( "Server (%s:%d) connected!\n", ip, port );
    //購読登録する
    mosquitto_subscribe( mosq, NULL, topic, 0 );

    //MQTTの受信を永久に待機する
    mosquitto_loop_forever(mosq, -1, 1);
    //(Ctrl+Cでプログラムを終了するまで)
    return 0;
}

//トピック受信時の処理
void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
{
    if(msg->payloadlen > 0)
    {
        //受信したpayloadには終端文字\0がないので追加する
        char msgtext[msg->payloadlen + 1];
        strncpy(msgtext, msg->payload, msg->payloadlen);
        msgtext[msg->payloadlen] = '\0'; //文字列終端文字を追加
        printf( "Message %s about %s received\n",
        msgtext, msg->topic );
    }
    else
    {
        printf("(null) about %s\n", msg->topic);
    }
}

//プログラム終了時の処理
void endCatch(int sig)
{
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();
    printf("End Program\n\n");
    exit(0);
}

ビルド

これをコマンドでビルドします.

Cファイルを作成した場所で以下のコマンドを実行します.

gcc MQTTsub.c -o MQTTsub -lmosquitto

コマンドの意味は

  • gcc : C言語をビルドするコマンド
  • MQTTsub.c : Cのファイル名(自分で作成したもの)
  • -o : ビルドした後の実行ファイルの名前を指定
  • MQTTsub : ビルドした後の実行ファイルの名前
  • -lmosquitto : ライブラリ「mosquitto」を使用する

です.

エンターキーを押して,エラーなどが出なければ成功です.

実行

以下のコマンドでプログラムを実行します.

./MQTTsub

(実際にはRaspberry Piで実行します.私はSSHでMacからRaspberry Piをリモート制御しています.)

f:id:masa_flyu:20190216120647j:plain

このように2行だけ出力されて停止するはずです.

データを受信すると,随時新しい行が追加されていきます.

送受信チェック

では作成した受信プログラムを送信プログラムとは違うRaspberry Piで実行してみましょう.

(同じRaspberry Piでも構いません.その場合はターミナルを2つ立ち上げてください.)

送信側でMQTTpubを受信側でMQTTsubをそのまま実行すれば良いです.

以下は左が受信側,右が送信側の画面です.

f:id:masa_flyu:20190216120304j:plain

このように「Hello MQTT」という文字列が送信されていることがわかります.

なお,CloudMQTTはアメリカまたはヨーロッパのサーバを介するため,150〜400[ms]遅延します.

(当方ではアメリカで175[ms],ヨーロッパで350[ms]程度で比較的安定していました)

参考

MQTT Client -C言語- - Qiita http://altenergy-system.com/archives/4172

C言語でMQTTクライアントを動作させる(paho.mqtt.embedded-c) - Symfoware

GitHub - CloudMQTT/mosquitto: Eclipse Mosquitto

当ブログをご利用いただく際には免責事項をお読みください。