JavaのMQTTクライアント

JavaのMQTTクライアント

1. 概要

このチュートリアルでは、Eclipse Paho projectが提供するライブラリを使用して、JavaプロジェクトにMQTTメッセージングを追加する方法を説明します。

2. MQTTプライマー

MQTT (MQ Telemetry Transport) is a messaging protocolは、産業用アプリケーションで使用されるような低電力デバイスとの間でデータを転送するためのシンプルで軽量な方法の必要性に対処するために作成されました。

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

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

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

3. プロジェクトのセットアップ

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


  org.eclipse.paho
  org.eclipse.paho.client.mqttv3
  1.2.0

Eclipse PahoJavaライブラリモジュールの最新バージョンはMavenCentralからダウンロードできます。

4. クライアント設定

Pahoライブラリを使用する場合、MQTTブローカーからメッセージを送受信するために最初に行う必要があるのは、obtain an implementation of the IMqttClient interfaceです。このインターフェイスには、アプリケーションが確立するために必要なすべてのメソッドが含まれています。サーバーへの接続、メッセージの送受信。

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);

この場合、we’re using the simplest constructor available, which takes the endpoint address of our MQTT broker and a client identifierは、クライアントを一意に識別します。

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

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

The server endpoint we’re using is a public MQTT broker hosted by the Paho project。これにより、インターネットに接続している人なら誰でも、認証を必要とせずにクライアントをテストできます。

4.2. サーバーへの接続

新しく作成したMqttClientインスタンスはサーバーに接続されていません。 We do so by calling its connect() method、オプションでプロトコルのいくつかの側面をカスタマイズできるMqttConnectOptions インスタンスを渡します。

特に、これらのオプションを使用して、セキュリティ資格情報、セッション回復モード、再接続モードなどの追加情報を渡すことができます。

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

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

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

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

  • ライブラリは、ネットワーク障害が発生した場合にサーバーへの再接続を自動的に試行します

  • 前回の実行からの未送信メッセージを破棄します

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

5. メッセージを送信する

すでに接続されているMqttClientを使用してメッセージを送信するのは非常に簡単です。 We use one of the publish() method variants to send the payload, which is always a byte array, to a given topic、次のサービス品質オプションのいずれかを使用します。

  • 0 –「最大1回」のセマンティクス。「fire-and-forget」とも呼ばれます。 このオプションは、メッセージの損失が許容される場合に使用します。これは、いかなる種類の確認応答または持続性も必要としないためです。

  • 1 –「少なくとも1回」のセマンティクス。 メッセージの損失が許容できない場合は、このオプションを使用します。andサブスクライバーは重複を処理できます

  • 2 –「1回だけ」のセマンティクス。 メッセージの損失が許容できない場合は、このオプションを使用します。andサブスクライバーが重複を処理できない

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

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

public class EngineTemperatureSensor implements Callable {

    // ... 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);
    }
}

The MqttMessage encapsulates the payload itself, the requested Quality-of-Service and also the retained flag for the message.このフラグは、サブスクライバーによって消費されるまでこのメッセージを保持する必要があることをブローカーに示します。

この機能を使用して、「最後の正常な」動作を実装できるため、新しいサブスクライバーがサーバーに接続すると、保持されたメッセージをすぐに受信できます。

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

MQTTブローカーからメッセージを受信するために、we need to use one of the subscribe() method variantsを指定できます。これにより、以下を指定できます。

  • 受信したいメッセージの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をスローすると、クライアントはシャットダウンされます。 Please note that this will result in loss of any messages sent with QoS level of 0

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

7. 結論

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

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

この記事に示されているコードは利用可能なover on GitHubです。