JavaのMQTTクライアント

1.概要

このチュートリアルでは、https://www.eclipse.org/paho/[Eclipse Pahoプロジェクト]によって提供されるライブラリーを使用して、JavaプロジェクトにMQTTメッセージングを追加する方法を説明します。

2. MQTT入門

  • MQTT(MQ Telemetry Transport)は、産業用アプリケーションで使用されるような低電力デバイスとの間でデータを転送するためのシンプルで軽量な方法の必要性に対処するために作成されたメッセージングプロトコルです。

IoT(Internet of Things)デバイスの人気が高まるにつれて、MQTTの使用が増え、OASISとISOによる標準化が進みました。

このプロトコルは単一のメッセージングパターン、つまりPublish-Subscribeパターンをサポートします。クライアントから送信される各メッセージには、ブローカーが購読中のクライアントにルーティングするために使用する「トピック」が含まれています。トピック名は“ oiltemp ”のような単純な文字列、または“ motor/1/rpm ”のようなパスのような文字列です。

メッセージを受信するために、クライアントは、正確な名前またはサポートされているワイルドカードの1つを含む文字列(マルチレベルトピックの場合は「#」、シングルレベルの場合は「+」)を使用して1つ以上のトピックを購読します。

3.プロジェクトの設定

PavenライブラリをMavenプロジェクトに含めるには、次の依存関係を追加する必要があります。

<dependency>
  <groupId>org.eclipse.paho</groupId>
  <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  <version>1.2.0</version>
</dependency>

https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.eclipse.paho%22%20AND%20a%3A%22org.eclipse.paho.clientの最新バージョン。 mqttv3%22[Eclipse Paho]JavaライブラリモジュールはMaven Centralからダウンロードできます。

4.クライアントの設定

Pahoライブラリーを使用するとき、MQTTブローカーからメッセージを送受信するために最初に必要なことは、 IMqttClient インターフェースの実装を取得することです。 ____このインタフェースには、サーバへの接続を確立し、メッセージを送受信するためにアプリケーションが必要とするすべてのメソッドが含まれています。

Pahoは、このインターフェースの2つの実装、非同期( MqttAsyncClient )と同期( MqttClient )を用意しています。

セットアップ自体は2段階のプロセスです。まず MqttClient クラスのインスタンスを作成し、次にそれをサーバーに接続します。次のサブセクションではこれらの手順について詳しく説明します。

4.1. 新しい IMqttClient インスタンスを作成する

次のコードスニペットは、新しい IMqttClient 同期インスタンスを作成する方法を示しています。

String publisherId = UUID.randomUUID().toString();
IMqttClient publisher = new MqttClient("tcp://iot.eclipse.org:1883",publisherId);

この場合、利用可能な最も単純なコンストラクタを使用します。これは、MQTTブローカのエンドポイントアドレスと、クライアントを一意に識別するクライアント識別子を取ります。

今回のケースでは、ランダムなUUIDを使用したため、実行ごとに新しいクライアント識別子が生成されます。

Pahoは、未確認メッセージの保存に使用される永続化メカニズムやプロトコルエンジンの実装に必要なバックグラウンドタスクの実行に使用される ScheduledExecutorService をカスタマイズするために使用できる追加のコンストラクタも提供します。

  • 私たちが使用しているサーバーエンドポイントは、PahoプロジェクトによってホストされているパブリックMQTTブローカー** です。これにより、インターネットに接続している人なら誰でも認証なしでクライアントをテストできます。

4.2. サーバーに接続する

新しく作成された MqttClient インスタンスはサーバーに接続されていません。

  • connect() メソッド** を呼び出すことでこれを行い、オプションでプロトコルのいくつかの側面をカスタマイズできるようにする __MqttConnectOptions __instanceを渡します。

特に、セキュリティ認証情報、セッション復旧モード、再接続モードなどの追加情報を渡すためにこれらのオプションを使用できます。

MqttConnectionOptions クラスは、これらのオプションを単純なプロパティとして公開します。これらは通常の設定メソッドを使用して設定できます。シナリオに必要なプロパティを設定するだけで済みます - 残りのものはデフォルト値を仮定します。

サーバーへの接続を確立するために使用されるコードは通常、次のようになります。

MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
options.setConnectionTimeout(10);
publisher.connect(options);

ここでは、接続オプションを次のように定義します。

  • ライブラリは自動的にサーバーに再接続しようとします。

ネットワーク障害のイベント ** 前回の実行からの未送信メッセージを破棄します

  • 接続タイムアウトは10秒に設定されています

5.メッセージを送る

すでに接続されている MqttClient を使用してメッセージを送信するのは非常に簡単です。 ** 次のサービス品質オプションの1つを使用して、 publish() メソッドバリアントの1つを使用して、ペイロード(常にバイト配列)を特定のトピックに送信します。

  • 0 - 「せいぜい1回」の意味で、「消し忘れ」とも呼ばれます。つかいます

メッセージの損失が許容できる場合、このオプションは必要ありません。 確認または持続性の種類 ** 1 - 「少なくとも1回」の意味メッセージ損失が発生したときにこのオプションを使用します。

あなたの購読者は重複を処理できません ** 2 - 「一度だけ」の意味メッセージ損失がない場合はこのオプションを使用してください。

あなたの加入者は重複を処理できません

このサンプルプロジェクトでは、 __EngineTemperatureSensor classが、その call()メソッドを呼び出すたびに新しい温度測定値を生成するモックセンサーの役割を果たします。

このクラスは Callable インタフェースを実装しているので、 java.util.concurrent パッケージで利用可能な ExecutorService 実装の1つで簡単に使用できます。

public class EngineTemperatureSensor implements Callable<Void> {

   //... private members omitted

    public EngineTemperatureSensor(IMqttClient client) {
        this.client = client;
    }

    @Override
    public Void call() throws Exception {
        if ( !client.isConnected()) {
            return null;
        }
        MqttMessage msg = readEngineTemp();
        msg.setQos(0);
        msg.setRetained(true);
        client.publish(TOPIC,msg);
        return null;
    }

    private MqttMessage readEngineTemp() {
        double temp =  80 + rnd.nextDouble() **  20.0;
        byte[]payload = String.format("T:%04.2f",temp)
          .getBytes();
        return new MqttMessage(payload);
    }
}
  • MqttMessage は、ペイロード自体、要求されたサービス品質、およびメッセージの retained フラグをカプセル化します** このフラグは、サブスクライバによって消費されるまでこのメッセージを保持する必要があることをブローカに示します。

この機能を使用して、「最後に確認された動作」を実装できます。そのため、新しい加入者がサーバーに接続すると、保持されているメッセージがすぐに受信されます。

6.メッセージを受信する

MQTTブローカーからメッセージを受信するには、 subscribe() メソッドの変種 のいずれかを使用する必要があります。

  • 受信したいメッセージの1つ以上のトピックフィルタ

  • 関連するQoS

  • 受信したメッセージを処理するためのコールバックハンドラ

次の例では、メッセージリスナを既存の IMqttClient インスタンスに追加して、特定のトピックからメッセージを受信する方法を示します。コールバックとメイン実行スレッドの間の同期メカニズムとして CountDownLatch を使用し、新しいメッセージが到着するたびにそれをデクリメントします。

サンプルコードでは、メッセージを受信するために別の IMqttClient インスタンスを使用しました。どのクライアントが何をするのかを明確にするためだけにしましたが、これはPahoの制限ではありません。必要に応じて、メッセージのパブリッシュと受信に同じクライアントを使用できます。

CountDownLatch receivedSignal = new CountDownLatch(10);
subscriber.subscribe(EngineTemperatureSensor.TOPIC, (topic, msg) -> {
    byte[]payload = msg.getPayload();
   //... payload handling omitted
    receivedSignal.countDown();
});
receivedSignal.await(1, TimeUnit.MINUTES);

上記で使用されている subscribe() バリアントは、2番目の引数として IMqttMessageListener インスタンスを取ります。

この場合、ペイロードを処理してカウンタを減少させる単純なラムダ関数を使用します。指定された時間枠(1分)内に十分な数のメッセージが到着しない場合、 await() メソッドは例外をスローします。

Pahoを使用するときは、メッセージ受信を明示的に確認する必要はありません。コールバックが正常に戻った場合、Pahoはそれを正常に終了したと見なして、サーバーに確認応答を送信します。

コールバックが Exception をスローした場合、クライアントはシャットダウンされます。 これにより、QoSレベル0 で送信されたメッセージがすべて失われることに注意してください。

QoSレベル1または2で送信されたメッセージは、クライアントが再接続されトピックに再度登録すると、サーバーによって再送信されます。

7.まとめ

この記事では、Eclipse Pahoプロジェクトが提供するライブラリーを使用して、JavaアプリケーションにMQTTプロトコルのサポートを追加する方法を説明しました。

このライブラリでは、低レベルのプロトコル詳細をすべて処理できるため、ソリューションの他の側面に集中できますが、メッセージの永続性など、内部機能の重要な側面をカスタマイズするための十分なスペースを確保できます。

この記事で示されているコードはhttps://github.com/eugenp/tutorials/tree/master/libraries-server[GitHubで利用可能]です。