MQTT

当初、長い求職期間になると思われたので Andoroid のプログラミング資格でも取ろうかと思っていたのですが、結構早く決まりそう、ということで、手じかに出来る勉強に変更。それが MQTT

MQTT の概要を理解し、簡単なプログラムは書けるようにと思い始めたのですが、最後の日本語処理で苦戦しました。MQTT のごく基本的な使われ方を考えるとトピックに日本語を使う必要性は少ないですし、メッセージ (ペイロード) も通常はセンサーの測定値が主ですから数値主体ですのでここでも日本語が使用されることはほとんど無いでしょう。ただ、単純に Pub/Sub ということを考えると日本語が使用される可能性は否定できず、かつ、さらっとインターネットを見た限りでは日本語を使った例というのもほとんど無いように思われましたので、ちょっと調べてみました。

MQTT の仕様を見る限りでは (v3.1)

となっています。UTF-encoded という記述も困るのですが、ここは現実的には UTF-8 のようです。ようです、というのは、深く考えずに Paho (python) や ruby-mqtt を動かすと UTF-8 でパブリッシュされます。そして mosquitto はそれをそのまま Subscriber に送りますので、Subscriber もそれを想定して作る必要があります。

ペイロードは仕様上はアプリで規定ですからどのようにエンコードしてもいいのでしょうけど、ここもやはり現実的には UTF-8 でやりとりすることになるのでしょう。

なお、サーバ (ブローカ) は Linux での mosquitto を使いました (mosquitto version 1.3.4 (build date 2014-08-08 09:26:34+0000))。また Publisher/Subscriber ともに Windows (Shift_JIS。厳密に言えば Windows-31J/MS932) で動かしています。したがって、Publish では Shift_JIS から UTF-8 への、Subscriber では UTF-8 から Shift_JIS への変換が必要です。

Publisher では、以下のようにして Publish します。特別なコードは必要ありません。


publish.single("マイトピック", payload="こんにちは MQTT!", hostname="mosquitto")

Subscriber では、以下のようにしてメッセージを取得します。


def on_message(client, obj, msg):
print("Topic:"+msg.topic+", QoS:"+str(msg.qos)+", Payload:"
+(msg.payload).decode('utf-8'))

Publisher では、以下のようにして Publish します。特


String topic = "マイトピック";
String payload = "こんにちは MQTT!";
int qos = 2; // 2 でなければいけないという意味ではない

MqttMessage message = new MqttMessage(payload.getBytes("utf-8"));
message.setQos(qos);
mqttc.publish(topic, message);

Subscriber では、以下のようにしてメッセージを取得します。


@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String payload = new String(message.getPayload(), "utf-8");
System.out.println(topic + ": " + payload);
}

上記コードは UTF-8 での PUBLISH の例ですが、"utf-8" を明示的に指定しない、つまり Windows であればデフォルトのエンコーディングである Windows-31J が使用されますが、Windows-31J のまま Publisher は mosquitto に送信され、Windows-31J のまま Subscriber は受信して、日本語の文字化けは起こりません。ただ、たとえば上記の Pyhton との混在、たとえば Publisher が Python で Subscriber が Java の場合は文字化けが発生します。mosquitto は UTF-8 で送信しているのに Subscriber 側は Windows-31J を想定しているからです。

Publisher では、以下のようにして Publish します。特別なコードは必要ありません。


host = 'mosquitto'
port = 1883

MQTT::Client.connect(:remote_host => host, :remote_port => port) do |mqttc|
mqttc.publish('マイトピック', 'こんにちは MQTT!')

この場合、Publisher は UTF-8 で送信しています。したがって Subscriber もそれを前提としたコードになるのですが、試行錯誤した結果、以下のようなコードとなりました。


host = 'mosquitto'
port = 1883

MQTT::Client.connect(:remote_host => host, :remote_port => port) do |mqttc|
mqttc.get('マイトピック') do |topic, message|
puts topic.encode("Shift_JIS")
puts message.force_encoding("UTF-8").encode("Shift_JIS")
end
end

おそらくもっときれいな書き方があるとは思うのですが、そこに行き着きませんでした。ruby-mqtt のソースを読み込めば何かわかるかもしれませんが、そこまでやるのが目的ではないので、現時点ではこのレベルに留めておきます。

MQTT の本来の目的を考えれば、実際に何らかのセンサーと組み合わせたほうが実用的だと思います。日本語が使えるかどうかは現実的にはあまり本質的ではないとは思いますが、ちょっと気になったので調べてみました。個人的には、スクリプト言語は中で何をやっているのかきちんと理解しないとはまるので、こういう場合は Java がわかりやすいと考えています。