Ruby で MQTT プロトコルを試す

MQTT とは TCP/IP 上で動作する通信プロトコルの名称で、HTTP よりも軽量・省電力という特徴がある。その特徴から消費電力・通信量の制約を受けやすい IoT デバイスとサーバー間での通信に向いており、仕様標準化も進んでいる。@moznion さんが言及 されているのを見て興味を持ち、Ruby で試してみた。Ruby では mqtt という gem が用意されており、手軽に試すことが出来る。

$ gem install mqtt --no-ri --no-rdoc

Broker

f:id:alea12:20171113100837j:plain

画像出典: Securing MQTT - BuildingIoT 2016 slides

MQTT プロトコルにおける通信では、データ送信元と送信先との間に Broker と呼ばれるサーバが介在する。データ送信者(Publisherと呼ばれる) はデータ受信者に対して直接データを送信するのではなく Broker に対してデータを送信し、Broker はそれを各受信者(Subscriber)に対して送信する。

MQTT 通信の試用環境としてオープンな(誰でも subscribe できる) Broker が用意されており、今回はこれを使うこととする。

Topic

MQTT プロトコルでデータを送受信する際には、Topic を指定する必要がある。Topic は最低 1 文字の ASCII で、大文字・小文字を区別する。詳しくは 仕様を確認 のこと。

Subscriber

ターミナルで pry を開き、以下のようにして Subscriber を立ち上げる。alea12/# というのは Topic Filter と呼ばれるもので、正規表現ほどの表現力はないものの、一定のワイルドカード的な用途に使える。

[1] pry(main)> require 'mqtt'
=> true
[2] pry(main)> server = 'test.mosquitto.org'
=> "test.mosquitto.org"
[3] pry(main)> channel = 'alea12/#'
=> "alea12/#"
[4] pry(main)> MQTT::Client.connect(server).get(channel) do |topic, msg|
[4] pry(main)*   puts "[#{Time.now}] #{topic}: #{msg}"
[4] pry(main)* end

Subscriber を立ち上げると、指定した Channel への Publish 待ち状態となる。このターミナルはこのまま残しておく。

Publisher

別のターミナルを立上げ、以下のようにすることで指定した Channel に対してメッセージを送信することができる。

[1] pry(main)> require 'mqtt'
=> true
[2] pry(main)> MQTT::Client.connect('test.mosquitto.org').publish('alea12', 'Hello, world!')
=> nil
[3] pry(main)> MQTT::Client.connect('test.mosquitto.org').publish('alea12/test', 'Hello world, again!')
=> nil

確認

先ほどのターミナルに戻って確認すると、以下のように送信したデータが受信できているはず。

[2017-11-13 10:32:32 +0900] alea12: Hello, world!
[2017-11-13 10:32:41 +0900] alea12/test: Hello world, again!

感想