MQTTで遊ぶ(Java)

すっかりブログ書くのを放置してしまいましたが、前回MQTTサーバを導入しましたので、実際にコード書いてみます。
お仕事でプログラム書かなくなって久しいですが一番書ける言語はやっぱりJavaなので、Javaで。

・・・といっても、ここに書いてあることを試すだけですが^^; eclipse.org

設定

pom.xmlファイルを用意し次のように記入し、Java用MQTTクライアントを入手します。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

(中略)
    <repositories>
        <repository>
            <id>Eclipse Paho Repo</id>
            <url>https://repo.eclipse.org/content/repositories/paho-releases/</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.1.0</version>
        </dependency>
    </dependencies>
</project>

これで、org.eclipse.paho.client.mqttv3-1.1.0.jarファイルが落ちてきました。

コード

次にコードを書きます。 コードの内容は、MQTTサーバに接続し、"test"のトピックに"Message from MqttPublishSample"というメッセージを投げるというものです。

※package文は省略

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class Sample {
    
        public static void main(String[] args) {
 
        String topic = "test";
        String content = "Message from MqttPublishSample";
        int qos = 0;
        String broker = "tcp://***.***.***.***:1883";
        String clientId = "JavaSample";
        MemoryPersistence persistence = new MemoryPersistence();
  
        try {
            MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setCleanSession(true);
            System.out.println("Connecting to broker: " + broker);
            sampleClient.connect(connOpts);
            System.out.println("Connected");
            System.out.println("Publishing message: " + content);
            MqttMessage message = new MqttMessage(content.getBytes());
            message.setQos(qos);
            sampleClient.publish(topic, message);
            System.out.println("Message published");
            sampleClient.disconnect();
            System.out.println("Disconnected");
            System.exit(0);
        } catch (MqttException me) {
            me.printStackTrace();
        }
    }
}

確認

MQTTサーバを立ち上げます。

sudo vernemq start

前回も使用したPaho Clientでサーバにつなぎ、"test"トピックをSubscribeしておきます。
f:id:xyzplus:20170211184347j:plain

そして、先ほど書いたJavaプログラムを実行。

  • プログラムのコンソール
    f:id:xyzplus:20170211184725j:plain

  • Paho Clientの画面
    f:id:xyzplus:20170211184529j:plain

最下行のReceivedにある通り、testトピックのJavaプログラムから発行したメッセージをPaho Clientで受信することが出来ました。

MQTTで遊ぶ(導入編)

MQTTとは

次のURL参照で(他力本願)

MQTT as a Service sango

ざっくり雑にまとめると、メッセージ配信に使用する軽量なプロトコルって感じでしょうか。

導入

MQTTを扱うサーバ(MQTTブローカーというらしい)は色々あるようですが、今回はVerneMQを使用します。 vernemq.com

パッケージをダウンロードしてインストール。

Download VerneMQ

今回はさくらのVPS上に導入しますのでRedHat用のパッケージを。
・・・なんですが、0.15.2のダウンロードリンクがなぜかsrc.rpmになっているのでURLを一部書き換える必要があります。(12/25現在)

設定

VerneMQの設定ファイルは次のところにあります。

  • /etc/vernemq/vernemq.conf

とりあえず動かすところを目標にしているので匿名ユーザーの接続をOKにします。
※実際にはVPN経由でしか繋がらない様にファイアウォールでポートふさいでいます。

allow_anonymous = on 

次に使用するポートの設定

listener.tcp.default = 0.0.0.0:1883
listener.ws.default = 0.0.0.0:8888

後は初期値のまま。

起動

sudo vernemq start

起動すると、ulimit -n の値が小さいと警告が出るので、値を変更して再起動。

  • /etc/security/limits.conf
vernemq          soft    nofile          65536
verne            hard    nofile          65536

※一時的に変更する場合は次のコマンドを実行

/sbin/sysctl -w fs.file-max = 65536

設定確認

次のコマンドを実行します。

sudo vmq-admin listener show
+------+-------+-------+-----+----------+---------+
| type |status |  ip   |port |mountpoint|max_conns|
+------+-------+-------+-----+----------+---------+
| vmq  |running|0.0.0.0|44053|          |  10000  |
|mqttws|running|0.0.0.0|8888 |          |  10000  |
| mqtt |running|0.0.0.0|1883 |          |  10000  |
+------+-------+-------+-----+----------+---------+

1883番と8888番ポートが開いて使えるようになりました。

動作確認

さくっと既製のクライアントを使用して動作を確認します。

Paho - Open Source messaging for M2M

ダウンロードしたファイルを解凍して起動します。

f:id:xyzplus:20161225201425j:plain

Connectionの設定

f:id:xyzplus:20161225201459j:plain

Server URIの欄は、tcp://IPアドレス:1883 と入力し、「Connect」ボタンをクリックして接続
StatusがConnectedになればOKです。

Subscriptionの設定

f:id:xyzplus:20161225201517j:plain

「+」ボタンをクリックすると図の様にTopicとQoSを入力できるようになります。
Topicは任意の値を入力(今回はtestにしました)、QoS0 - At Most Onceを選択し、「Subscribe」ボタンをクリックします。

左側のHistoryタブにSubscribedと出ればOKです。

f:id:xyzplus:20161225201543j:plain

メッセージの発行

では実際にメッセージを発行します。

f:id:xyzplus:20161225201612j:plain

TopicはSubscriptionで設定した値(test)を入力し、Messageに任意の文言を入力したら、「Publish」をクリックします。

f:id:xyzplus:20161225201624j:plain

History欄にPublishedとReceivedのメッセージが出ています。
(今回発行と購読が一緒のマシンなので両方出ます)

f:id:xyzplus:20161225201636j:plain

Last Message欄をみると、メッセージがちゃんと受信できています。

無事動作できているようです。
次回は実際にコード書いて同様の動きを試してみます。

VPSサーバ立て直してやった事 (ユーザー追加, SSH公開鍵認証, VPN)

ブログをはてブロに移し終わったので、これまでブログおいていたさくらのVPSをリセットしました。

サーバの構築手順はググれば沢山出てくるし、いたってふつーの事しかやっていませんが、この後Ansible使って初期構築を自動化を企んでいるってのもあるので、それ用に作業内容を残しておきます。

※さくらのVPSで動かすことを前提としています
※systemctlコマンドも省いています、必要に応じてenable/disableするって感じで

OSアップデート

※標準OSインストールでCentOS入れたらupdate済みのようですが、念のため。。。

# yum update

ユーザー追加

# useradd -G wheel ユーザー名
# passwd ユーザー名
Changing password for user ******.
New password:         #パスワード入力
Retype new password:  #もう1度パスワード入力
passwd: all authentication tokens updated successfully.

SSH公開鍵認証

  • /etc/ssh/sshd_config ※変更箇所のみ抜粋
変更前:  #PermitRootLogin yes  
変更後:  PermitRootLogin no

変更前:  PasswordAuthentication yes  
変更後:  PasswordAuthentication no

その後、公開鍵を作成してアップロード(id_rsa.pub)してコマンド実行

# mkdir /home/ユーザー名/.ssh
# chown ユーザー名:グループ名 /home/ユーザー名/.ssh
# chmod 700 /home/ユーザー名/.ssh
# mv /アップロード先/id_rsa.pub /home/ユーザー名/.ssh/authorized_keys
# chown ユーザー名:グループ名 /home/ユーザー名/.ssh/authorized_keys
# chmod 600 /home/ユーザー名/.ssh/authorized_keys

VPNサーバ(SoftEther)設定

DLしてインストール

# cd /tmp/
# wget http://jp.softether-download.com/files/softether/v4.22-9634-beta-2016.11.27-tree/Linux/SoftEther_VPN_Server/64bit_-_Intel_x64_or_AMD64/softether-vpnserver-v4.22-9634-beta-2016.11.27-linux-x64-64bit.tar.gz
# tar xvzf softether-vpnserver-v4.22-9634-beta-2016.11.27-linux-x64-64bit.tar.gz
# cd vpnserver/
# make
--------------------------------------------------------------------

SoftEther VPN Server (Ver 4.22, Build 9634, Intel x64 / AMD64) for Linux Install Utility
Copyright (c) SoftEther Project at University of Tsukuba, Japan. All Rights Reserved.

--------------------------------------------------------------------


Do you want to read the License Agreement for this software ?

 1. Yes
 2. No

Please choose one of above number:    # 1を入力

(中略)

Did you read and understand the License Agreement ?
(If you couldn't read above text, Please read 'ReadMeFirst_License.txt'
 file with any text editor.)

 1. Yes
 2. No

Please choose one of above number:    # 1を入力

Did you agree the License Agreement ?

1. Agree
2. Do Not Agree

Please choose one of above number:    # 1を入力

(中略)
--------------------------------------------------------------------

make[1]: Leaving directory `/tmp/vpnserver'

# cd ../
# mv vpnserver /usr/local

設定ファイルの作成

  • /usr/local/vpnserver/setup_vpnserver.sh ※新規作成
#!/bin/sh
sleep 3
tap_count=`nmcli d | grep tap_vpn | wc -l`
if [ $tap_count -eq 1 ]
then
    result=`ip addr add IPアドレス/サブネットマスク dev tap_vpn`
    exit $result
fi
  • /usr/lib/systemd/system/vpnserver.service ※新規作成
[Unit]
Description=SoftEther VPN Server
After=network.target local-fs.target

[Service]
Type=forking
ExecStart=/usr/local/vpnserver/vpnserver start
ExecStartPost=/usr/local/vpnserver/setup_vpnserver.sh
ExecStop=/usr/local/vpnserver/vpnserver stop

[Install]
WantedBy=multi-user.target

そのあと、次のコマンドを実行

# cd /usr/local/vpnserver/
# chmod 600 *
# chmod 700 vpncmd
# chmod 700 vpnserver
# chmod 700 setup_vpnserver.sh
# firewall-cmd --add-port=500/udp --permanent
# firewall-cmd --add-port=4500/udp --permanent
# firewall-cmd --add-port=5555/tcp --permanent
# firewall-cmd --zone=public --add-masquerade --permanent
# firewall-cmd --reload

SoftEtherのコンフィグ(vpn_server.config)はあらかじめ作っておいて、/usr/local/vpnserver/vpn_server.configにアップロード

Raspberry Piのiptablesを設定

(注)この記事は2015年5月9日に旧ブログに投稿したものです。今でも有効な内容かは不明・・・

iptablesの設定内容を永続化(起動時に自動的に読み込む)ためのパッケージをインストールします。

sudo aptitude install iptables-persistent

iptablesのコマンドをポチポチ叩いて設定します。
コマンドの詳細は以下のURLを参照
Linuxコマンド集 – 【iptables】パケットフィルタリングを設定する:ITpro
iptablesの設定方法|さくらインターネット公式サポートサイト

なお、今回

インターネット — ホテル有線LAN — Raspberry Pi無線LANスマホ

という通信をさせたかったので、iptablesにNAPT(IPマスカレード)の設定を入れます。

sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

注)この設定で正しくホテルで使えるかは試していないので不明です…

iptablesの設定内容を保存します。

sudo iptables-save /etc/iptables/rules.v4

ちなみにこんな感じのファイルが出来上がりました。
(一部編集しています)


# Generated by iptables-save v1.4.14 on Tue May  5 07:57:35 2015
*filter
:INPUT DROP [11:3724]
:FORWARD ACCEPT [4480:2695254]
:OUTPUT ACCEPT [228:27001]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
COMMIT
# Completed on Tue May  5 07:57:35 2015
# Generated by iptables-save v1.4.14 on Tue May  5 07:57:35 2015
*nat
:PREROUTING ACCEPT [145:12075]
:INPUT ACCEPT [1:52]
:OUTPUT ACCEPT [15:1234]
:POSTROUTING ACCEPT [2:288]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Tue May  5 07:57:35 2015

ラズパイのGUIを遠隔で操作(VNCサーバ構築)

(注)この記事は2015年5月4日に旧ブログに投稿したものです。今でも有効な内容かは不明・・・

色々なソフトの組み合わせを試してみましたが、自分の使い方ではこれが一番しっくりしたのでその方法をまとめます。

tightvncserverの導入

インストールします。

sudo aptitude install tightvncserver

まずは手動で起動してみます。
初回の起動時に初期パスワードを聞いてきますので、適当に入力。

vncserver

You will require a password to access your desktops.

Password:********
Verify:********
Would you like to enter a view-only password (y/n)? n

New 'X' desktop is raspberrypi:1

Creating default startup script /home/pi/.vnc/xstartup
Starting applications specified in /home/pi/.vnc/xstartup
Log file is /home/pi/.vnc/raspberrypi:1.log

これでVNCサーバが立ち上がりました。
PCから繋いでみます。

f:id:xyzplus:20161210010243p:plain

ポート番号は5900 + vncserver起動時に表示されたディスプレイ番号

f:id:xyzplus:20161210010258p:plain

無事接続できているようです。
ここでVNCサーバのメニューからログアウトを選択すると、VNCサーバを再起動するまで使えなくなりますので、ログアウトせずビューアを終了します。

VNCサーバを終了します。

vncserver -kill :1
Killing Xtightvnc process ID 2326

当然ですが、VNCサーバ終了後はビューアで接続を試みても接続できません。

xinetdの導入

上記の方法では使っていないときでもVNCサーバが常駐します。まぁサーバってそういうもんなんですが。
頻繁に使用する場合であれば起動しっぱなしでもいいですが、そうでない場合はリソースの無駄遣いです。
ということで、スーパーサーバ(xinetd)を使用して必要なときだけVNCサーバを起動することにします。

まずはxinetdをインストール

sudo aptitude install xinetd

VNCで使用するポート番号をxinetdの設定で使用できるように、/etc/servicesファイルに以下を追記します。
追記場所はどこでもOK

vnc             5901/tcp

続いて、xinetdからVNCサーバを起動するための設定ファイルを作成します。

/etc/xinetd.d/vnc (新規作成)

service vnc
{
        socket_type     = stream
        wait            = no
        user            = nobody
        server          = /usr/bin/Xvnc
        server_args     = -inetd -query localhost -once -geometry 1024x768 -depth 16 -rfbauth /etc/vnc_passwd
        disable         = no
}

server_argsの設定(Xvnc起動パラメータ)はここを参考
http://www.tightvnc.com/Xvnc.1.php

-rfbauth で指定した個所にパスワードファイルを作成します。

sudo vncpasswd /etc/vnc_passwd

作成後、パーミッションを変更してOtherのRead権限を付加します。
(本当はやりたくないんですが、これやらないとログインに失敗します。)

sudo chmod o+r vnc_passwd

LightDMの設定

xinetd経由で起動するようにした場合、LightDM(ディスプレイマネージャ)の設定も必要です。
Raspbianであれば既にインストールはされているので、設定ファイルを変更します。

/etc/lightdm/lightdm.conf (変更箇所のみ)

[LightDM]
(中略)
xserver-allow-tcp=true  ←追加

[SeatDefaults]
(中略)
#autologin-user=pi  ←コメントアウト

[XDMCPServer]
enabled=true ←アンコメント

ちなみにこれ、raspi-configの『3 Enable Boot to Desktop/Scratch』で設定を変更すると、
/etc/lightdm/lightdm.confの一部が書き換わるみたいです。

最後に、LightDMを自動起動するように変更します。

sudo update-rc.d lightdm enable