MQTTとMessagePub+ :応答系トピック


要求系トピックに対して要求メッセージを送った後、それを受けたクライアントは何らかの処理を行います。要求した側は、その処理結果を知りたいことがあります。このような時に利用されるのが、応答系トピックです。応答系トピックを使わなくても、処理を行った結果、状態が変化した場合、それを通知系トピックにパブリッシュすれば、間接的に処理結果を知ることができます。では、応答系トピックと、通知系トピックの違いはどんなところにあるのでしょうか。

通知系トピックは、通知を受けたい任意のクライアントがサブスクライブしますが、応答系トピックをサブスクライブするのは、対応する要求を行ったクライアントだけです。また、通知系トピックは、要求系トピックからの要求メッセージ以外の原因、例えば人による操作などで状態が変化した時も、メッセージ送信に使われるのに対して、応答系トピックにメッセージを送るのは、要求系トピック経由で要求メッセージを受けた時だけです。さらに、もし、要求の内容を判断した結果、状態変化が生じなかった場合でも、応答系トピックにメッセージを送ります。

トピック設計の主体


応答系トピックの設計の主体は、少し複雑です。応答系トピックは、応答を受ける側、つまり要求する側に対応する形で作ります。しかし、応答の内容は、応答する側、つまり要求を受ける側主体で決定します。応答系トピックは、MQTT v5の機能を用いて作ります。
まず、要求する側がMQTTブローカに接続する際、CONNECTパケットに、Request Response Informationプロパティに1を設定します。これは、MQTTブローカに「Response Informationを作成してください」とリクエストするプロパティです。これを受けたMQTTブローカは、接続応答のCONNACKパケットにResponse Informationプロパティを設定して返します。このResponse Informationが、応答系トピックのトピック名となります。 なお、Request Response Informationプロパティを設定しない、または0を設定した場合には、リクエストしないことを意味します。

6661_12.png

応答系トピックの名前は、MQTTブローカによって生成されます。

MQTTブローカによって生成された応答系トピックは、クライアントのセッションが維持されている間、維持されます。MessagePub+ ブローカでは、セッションと、既に生成された応答系トピックが維持されている状態で、Request Response Informationプロパティを1に設定してCONNECTパケットを受信した場合、CONNACKパケットに、Response Informationcプロパティとして、維持されている応答系トピックの名前を返します。これは、前回の接続で返されたResponse Informationと同じ内容となります。

分割単位

応答系トピックは分割しません。ひとつのMQTTクライアントに対してひとつの応答系トピックが割り当てられます。このトピックを、そのクライアントが行う全ての要求で共有します。

要求と応答のしくみ

応答系トピックは、MQTTブローカによって決定され、接続してきたクライアントにだけ通知されます。そのトピック名を知っているのは、応答を受ける側のクライアントだけです。では、どうやって要求に対する応答をパブリッシュするのでしょう。まず、応答を受けるクライアントは、応答系トピックをサブスクライブします。これは、接続時、CONNACKを受信した直後に行うのが一般的です。

6661_2.png

要求を行う時、要求系トピックにパブリッシュするわけですが、ここで、PUBLISHパケットにResponse Topicプロパティを設定します。その内容にとして応答系トピックを指定します。要求を受ける側は、このメッセージを受信し、処理します。この例では、照明デバイスがONというメッセージを受け、照明ON制御を行い、成功したので、成功という応答メッセージを準備します。そして、Response Topicとして指定された応答系トピックに対して、応答をパブリッシュします。それを、要求した側が受信することで、応答が要求元に届きます。要求の結果、どのような応答の種類が発生し得るのか知っているのは要求を受ける側ですので、要求の内容と同様、応答の内容も、要求を受ける側が決めます。応答系トピックの一番の特徴は、応答する側があらかじめトピックを知っているのではなく、要求系トピックのメッセージの内容(Response Topicプロパティ)から、応答系トピックの情報を取得し、それに対して応答をパブリッシュする点です。これにより、「照明制御」トピックに対して、様々な要求者がメッセージを送ってきたとしても、それぞれに応じた宛先に、応答メッセージを返信することができます。郵便に例えると、応答系トピックは返信用封筒のイメージです。

6661_3.png

応答の区別

要求する側は、ひとつの応答系トピックで全ての応答を受け取ります。要求を送信した後、必ず応答を受けるまで待ってから、次の要求を行うような同期的な設計ならば、応答はひとつ前に送った要求に対応することが自明です。しかし、これでは処理に時間がかかってしまうため、一度にたくさんの要求を、様々な相手に送信し、後でまとめて結果を受けるような、非同期的な設計を行いたいことがあります。このような場合、受信した応答が、どの要求に対応するのか、どうやって区別すれば良いのでしょうか。実はそのためのプロパティが用意されています。Correlation Dataプロパティです。内容は2バイトの長さ情報に続いて、その長さ分のバイト列が0-65535バイト続くフォーマットとなっています。Response Topicプロパティと同じように、要求する側が、PUBLISHパケットのプロパティにCorrelation Dataを設定します。その際、Correlation Dataをキーとして、どんな要求を行ったのかや、期待する応答を取得できるマップにデータを追加しておきます。要求を受けた側は、Correlation Dataプロパティをそのまま応答のPUBLISHパケットに設定します。こうすることで、要求した側が応答を受信した時、Correlation Dataを取得できるので、これをキーに要求情報を取得することができます。

6661_4.png

応答メッセージの内容は、対象毎に異なる可能性がありますが、Correlation Dataをキーとして要求情報を得ることで、期待する応答フォーマットなどを知ることができます。

この例では、説明をわかりやすくするために、Correlation Dataとして1と2を設定しました。しかし、セキュリティを考慮すると、Correlation Dataには推測できない値を設定すべきです。MQTTの規格範囲外になりますが、応答系トピックの権限について考えてみます。

MQTTブローカの実装によりますが、応答系トピックをサブスクライブする権限は、応答を受けるクライアントにのみ与えれば良いでしょう。そのクライアントが接続してきたときに、応答系トピックを生成し、そのクライアントにサブスクライブ権限を与えるわけです。では、パブリッシュ権限はどうすべきでしょうか。これまで見てきたように、要求系トピックをサブスクライブしている全てのクライアントが、応答系トピックにパブリッシュする可能性があります。これらのクライアントをあらかじめ全て把握することは困難です。よって、全てのクライアントにパブリッシュ権限を与えるのが現実的な落としどころといえるでしょう。MessagePub+ でも、Request Response Informationによって生成される応答系トピックをサブスクライブする権限は生成要求してきたクライアントに限定され、パブリッシュする権限は全てのクライアントに設定されます。

応答系トピックは、要求系トピックにパブリッシュが行われた際、要求を受ける側にResponse Topicプロパティとして通知されます。悪意のあるクライアントに、その通知された応答系トピックを公開、共有されてしまうと、他のクライアントからも応答系トピックにパブリッシュができてしまいます。つまり、なりすまし応答ができてしまうのです。ここで、Correlation Dataが重要になります。もし連番などの予測が容易な値であれば、なりすましも容易です。しかし、推測が困難な値であれば、なりすまし応答のパブリッシュ自体は可能ですが、Correlation Dataが一致することはないため、要求した側は単にその応答を無視すれば問題ありません。一致しなくても応答パブリッシュを連続で送信してMQTTブローカに負荷をかけることは可能ですが、そのようなクライアントは切断して、以降の接続を受け付けないようにすることも可能でしょう。

メッセージの内容

メッセージの内容は要求を受ける側主体で決めます。メッセージには、要求に対する結果を含めます。デバイス制御の場合であれば、実際にデバイスを制御した結果です。制御要求が失敗した場合のエラーコードの種類などは、要求を受ける側によって変わるでしょう。また、必要に応じて、付随する情報、例えば実際に制御した時刻のタイムスタンプ情報などを含めます。構造化も必要に応じて行います。

システムを設計する際は、Request/Responseの仕組み、Correlation Dataの扱い方は、接続する全てのクライアントで遵守するようにします。その上で、要求系トピックのメッセージの内容、応答系トピックのメッセージの内容は、要求を受ける側が決めて公開し、それに従う形で要求する側を設計します。

なお、通常、応答メッセージにRETAINフラグをセットすることはありません。


MQTTとMessagePub+

MQTTとMessagePub+ 目次に戻る

※この記事に掲載されている内容、および製品仕様、所属情報(会社名・部署名)は公開当時のものです。予告なく変更される場合がありますので、あらかじめご了承ください。

関連サービス