はじめに
IoT Hubと接続しているデバイスの通信状態をなんとなく理解したいけどSDKの中身を全部読むスキルは無いので、とりあえずWiresharkを使って出入りを確認してみました。
利用するのはIoT HubのS1とC#のサンプル(と付随するアレコレ)です。
通信の内容までは見ていません(TLSの中身にはタッチしていない)。
Wiresharkで見て取れた範囲だけを確認しています。
"なぜそのような通信になるのか"には触れていませんし、仕様の裏どりもしていません。
結論
通信頻度が多い場合は、MQTTかAMQPがデバイスに優しそうな雰囲気でした。
ちなみにデバイスSDKを利用すると、ポートが閉じていれば勝手にWebSocket(443)にしてくれます。
1. 準備
1-1. IoT Hubの作成
1-2. デバイスIDの作成
できたデバイスの接続文字列は後程利用しますのでコピーしておきます。
1-3. Wiresharkインストール
(省略)入れました。
1-4. サンプルアプリのダウンロード
こちらにも記載のありますサンプルをダウンロードします。
今回使うのは"azure-iot-samples-csharp-master\iot-hub\Quickstarts\SimulatedDevice"です。
中のProgram.csファイルに”{Your device connection string here}”という記載はありますので、1-2でコピーした値に変更します。
2. 実行
2-1.環境の確認
IoT Hubのホスト名でnslookupして、現在のIPアドレスが"20.43.70.160"だとわかりました。(余談:これは変化するので、固定値で書かないでください)
PCのIPアドレスもipconfigして "192.168.0.13" だとわかりました。
2-2. Wireshark実行
"port 8883"と入れてEnterしました。(余談:8883はMQTTのポートです。サンプルアプリはデフォルトがMQTTを利用していました。)
2-3. アプリを実行
数回テレメトリーを送信し、その後Ctrl+Cで終了コマンドを発行しました。
結果はこのようになりました。
PCのIPは192.168.0.13、アプリの利用ポートは56205、IoT HubのIPは20.43.70.160、ポートは8883で、当たり前ですがPCから通信を開始しています。
3. 結果の確認
最初の3行で、TCP接続しています。
[SYN] [SYN, ACK] [ACK]の例の子です。
次の数行で、TLSネゴシエーションしています。
Hello Helloの例の子です。
そのあとがデバイスとIoT Hubのやりとりになっています。
何回か流して眺めた感想:
・PCからデータが流れる前にアプリとIoT Hubの間で事前準備をしている(↑スクリーンショット前半)
・PCからデータを流すとIoT HubからTLSで返事が返ってきて、それにTCPで[ACK]を返して通信1往復している(↑スクリーンショット後半)
("受け取ったよ"は雑だけど、今回は見えないんだから良し。)
切断は実施タイミングによって結果がいろいろですが
・TLSベースでPCから切断通知
・TCPベースでIoT Hubから切断通知
・TCPベースでPCから切断了解通知
・TCPベースでPCから切断通知
・TCPベースでIoT Hubから切断了解通知
だいたいこんなような情報が入っていました。
4. 死活監視の挙動を確認
サンプルアプリケーションの最後のほうに**await Task.Delay(1000);と記載があります。
1秒Delayしてループしていますので、ここをawait Task.Delay(1000000);**としてみます。
(初回のメッセージ送付後、ずっと通信しないで待てば良いので、数字は適当です。)
Delayがとても長くなりました。
これで
・1回目の通信がきたからお互いに接続した
・通信がこないので、IoT HubはPCの状態がわからない
・PCも実はIoT Hubからの通信がこないので状態がわからない
という、いつ切断して良いかわからない状態になっています。
そこで、お互いに死活監視します。
結果はこのようになりました。
後半No.25からが死活監視の挙動です。
PCからPing、IoT Hubから返事、PCからTCPベースで[ACK]の3つがセットで続きます。
5. Wi-Fi切ったらどうなるか確認
通信間隔を10秒にして、その間にWi-FiをOFFしてONすると、正常に動作を続けました。
途中で通信が途絶えていたことには気づいていない模様でした。
(まぁ当然といえば当然ですが。)
次に、通信間隔を1秒にして、通信しようとしたら切れている状態を試しました。
通信回線が復旧すると、TCPの再接続要求が出て通信が再開します。
状況によっては、クライアント側の通信ポートを変更して、別のTCP接続を始めているパターンもありました。
最後に接続するWi-Fiそのものを変更してみました。
変更と同時に新しいIPアドレスからTCP接続が始まりました。(上部のグレーの部分)
その後、前に利用していたTCP接続は切断しています。(下部のグレーの部分)
こういった動作がきちんとしていれば、移動体で利用しても安心だと思います。
6. ほかのプロトコルはどうか
TransportType.Mqtt;
こちらのMQTTというところだけを変更して通信を確認してみました。
TransportType.Mqtt_WebSocket_Only;
・TLSの部分若干違う
・Portが443
・メッセージ送信がさきほど3行1セットだったのが2行1セット
PCからTLSベースでメッセージを送信すると、MQTTだとTLSベースの返事がありましたが、WebSocketだとIoT Hubから直接[ACK]が返却されていました。
TransportType.Amqp;
・通信開始前の頭出しが長い
・Portが5671
・死活監視するとIoT Hub側からも監視している(↑スクリーンショットのNo.39)
TransportType.Amqp_WebSocket_Only;
・Portが443
TransportType.Http1;
・Portが443
・メッセージはPCが[ACK]を送って終わり(今まではIoT Hubから[ACK]が返って終わり)
・TCPとTLSが生きている間は使い続けてくれている
・死活監視の代わりに[RST]が返ってきて終わる
・終了時はTCPの[FIN]と[ACK]だけなのでシンプル
TransportType.MQTT;
MQTTを指定しておくと、デフォルトでPort8883を利用します。
しかし、Portがブロックされていると443で通信を始めました。
↑見にくいですが、こうする(Port8883をブロックする)とMQTT over WebSocket(443)に切り替えて通信を始めます。
7. さいごに
今回は、面倒だから見ないようにしていた通信をフンワリ確認してみました。
まぁ標準的で当たり前な動きをしているな、というのが感想です。
とはいえ、1度は確認しておきたかったので勉強になりました。
ブローカーを立てて維持するのは面倒なので、IoT Hubを使うのはいい感じだと思います。