1. はじめに
前回の記事「新人研修や自習にも!3分でサクッと理解するMQTT入門 ─ HTTPとの違いとIoT活用💡」では、MQTTの概念やHTTPとの違いをイメージでつかむことを目指しました。
今回はその続きとして、いよいよ 自分のPC上でSocketDebuggerを使い、MQTT通信を手で動かしてみる 実践編です。
TCPペイロードに正しいMQTTフォーマットを手作業で配置し、CONNECT/SUBSCRIBE/PUBLISH の一連の流れを体験します。
手作業なので実用性は低いですが、そのぶん MQTTのプロトコル構造をバイト単位でじっくり理解できる 貴重な機会です。
「プロトコルを深く理解したい」「通信の中身を直接見てみたい」という方にぴったり。新人研修や自習として、ぜひ挑戦してみてください!
2. 環境準備
まずは実験環境を整えましょう。本記事では 自分のPC上でSocketDebuggerを2つ起動 して、1つを送信側(Publisher)、もう1つを受信側(Subscriber)として使用します。
必要なもの
- SocketDebugger(最新版をインストール)
-
インターネット接続(無料MQTTブローカに接続するため)
例:test.mosquitto.org ポート 1883 - 基本的な TCP/UDP通信の知識(理解がスムーズになります)
接続のイメージ
- SocketDebugger①(Publisher)
・MQTTパケットを手作業で作成
・MQTTブローカに CONNECT → PUBLISH を送信 - SocketDebugger②(Subscriber)
・MQTTパケットを手作業で作成
・MQTTブローカに CONNECT → SUBSCRIBE を送信
・Publisherから届いた PUBLISH メッセージを受信
ここでのポイント
- 両方のSocketDebuggerで手作業によるパケットを作ることで、MQTTの通信の流れをバイト単位で理解できます
- 同じPCでも2つのSocketDebuggerを起動可能です
- MQTTブローカは無料で使えるものを使用するので、すぐに実験を始められます
これで、手作業でのMQTT通信実験の準備 は完了です。
3. MQTTパケット構造の解説
MQTT通信を手作業で体験するためには、まず 各パケットの構造 を理解する必要があります。
本章では CONNECT / SUBSCRIBE / PUBLISH の3種類のパケットを例に、Hexペイロードをバイト単位で解説します。
3.1 MQTTバージョンについて
MQTTにはいくつかのバージョンがありますが、本記事では MQTT 3.1.1(プロトコルレベル4) を使用します。
- 理由
- 無料MQTTブローカでも標準的に対応している
- CONNECTパケットがシンプルで、手作業でバイトを組み立てやすい
- 初心者でも理解しやすく、SocketDebuggerでの実践に最適
- CONNECTパケットで指定する内容
- プロトコル名:MQTT
- プロトコルレベル:0x04
注意
- MQTT 5.0ではプロパティなどが追加されるため、手作業での解析や送信は難易度が高くなります
- 実践編としては、まずMQTT 3.1.1で理解を深めることをおすすめします
3.2 CONNECTパケット
CONNECTパケットは、クライアントがMQTTブローカに接続する際、最初に送るパケットです。
セクション | 項目名 | サイズ | 内容 | 備考 |
---|---|---|---|---|
Fixed Header | パケットタイプ & フラグ | 1バイト | 0x10 | CONNECTパケットは常にこの値 |
残りの長さ(Remaining Length) | 1〜4バイト | 例:0xC8 0x01(200バイト) | Variable Header + Payloadの合計サイズ | |
Variable Header | プロトコル名の長さ | 2バイト | 0x00 0x04 | 常に4(MQTT) |
プロトコル名 | 4バイト | 0x4D 0x51 0x54 0x54 | "MQTT"(固定) | |
プロトコルレベル | 1バイト | 0x04 | MQTT v3.1.1 | |
接続フラグ | 1バイト | 例:0xC2 | 認証やWillメッセージの有無を示す | |
キープアライブ | 2バイト | 例:0x00 0x3C(60秒) | 通信がないときのタイムアウト時間 | |
Payload | クライアントIDの長さ | 2バイト | 例:0x00 0x04 | IDの文字数 |
クライアントID | Nバイト | 例:0x74 0x65 0x73 0x74 | "test"など | |
Will Topic(任意) | 2 + Nバイト | 省略可 | WillフラグがONのときのみ | |
Will Message(任意) | 2 + Nバイト | 省略可 | WillフラグがONのときのみ | |
ユーザー名(任意) | 2 + Nバイト | 省略可 | ユーザー名フラグがONのときのみ | |
パスワード(任意) | 2 + Nバイト | 省略可 | パスワードフラグがONのときのみ |
ビット位置 | 名前 | 値が1のときの意味 | 備考 |
---|---|---|---|
7 | ユーザー名フラグ | ユーザー名がPayloadに含まれる | 認証に使用 |
6 | パスワードフラグ | パスワードがPayloadに含まれる | 認証に使用 |
5 | Will Retain | Willメッセージを保持する | Will QoSと併用 |
4〜3 | Will QoS | WillメッセージのQoSレベル(0〜2) | 2ビットで表現 |
2 | Willフラグ | Willメッセージを送信する | TopicとMessageがPayloadに含まれる |
1 | Clean Session | セッションを新規に開始する | 前回の状態を保持しない |
0 | 予約 | 常に0 | 使用禁止(仕様で定義) |
3.2.1 CONNACKパケット
CONNACKパケットは、クライアントがCONNECTパケットを送った後、MQTTブローカ(サーバー側)が応答として返すパケットです。
セクション | 項目名 | サイズ | 内容 | 備考 |
---|---|---|---|---|
Fixed Header | パケットタイプ & フラグ | 1バイト | 0x20 | CONNACKパケットは常にこの値 |
残りの長さ(Remaining Length) | 1バイト | 0x02 | Variable Headerのサイズ(2バイト) | |
Variable Header | 接続確認フラグ(Session Present) | 1バイト | 0x00 または 0x01 | Clean SessionがOFFのときにセッションが残っているか |
接続応答コード(Connect Return Code) | 1バイト | 0x00〜0x05 | 接続結果(成功・失敗の理由) |
コード | 意味 | 説明 |
---|---|---|
0x00 | 接続成功 | 正常に接続された |
0x01 | 不正なプロトコルバージョン | Protocol Levelがサポートされていない |
0x02 | 識別子拒否 | Client IDが不正または重複 |
0x03 | サーバー利用不可 | MQTTブローカが一時的に利用できない |
0x04 | 認証情報不正 | ユーザー名またはパスワードが不正 |
0x05 | 認証拒否 | 認証に失敗した |
3.3 SUBSCRIBEパケット
SUBSCRIBEパケットは、クライアントがMQTTブローカに「このトピックのメッセージを受け取りたい」とリクエストするために送るパケットです。
セクション | 項目名 | サイズ | 内容 | 備考 |
---|---|---|---|---|
Fixed Header | パケットタイプ & フラグ | 1バイト | 0x82 | SUBSCRIBEはタイプ8、Flagsは必ず0010(QoS 1) |
残りの長さ(Remaining Length) | 1〜4バイト | 例:0x0A(10バイト) | Variable Header + Payloadの合計サイズ | |
Variable Header | パケット識別子(Packet Identifier) | 2バイト | 例:0x00 0x0A | SUBACKとの対応に使うID |
Payload | トピックフィルターの長さ | 2バイト | 例:0x00 0x05 | トピック名の文字数 |
トピックフィルター + QoS | N + 1バイト | 例:`topic` + `0x01` | 購読するトピック名と希望QoS |
QoS | 意味 | 説明 |
---|---|---|
0 | At most once | 最低1回(届かない可能性あり) |
1 | At least once | 最低1回(重複する可能性あり) |
2 | Exactly once | 重複なしで1回だけ(最も信頼性が高い) |
3.3.1 SUBACKパケット
SUBACKパケットは、クライアントが送ったSUBSCRIBEパケットに対して、MQTTブローカが「その購読リクエストを受け付けました」と応答するために返すパケットです。
セクション | 項目名 | サイズ | 内容 | 備考 |
---|---|---|---|---|
Fixed Header | パケットタイプ & フラグ | 1バイト | 0x90 | SUBACKはタイプ9、Flagsは0000(固定) |
残りの長さ(Remaining Length) | 1〜4バイト | 例:0x03(3バイト) | Variable Header + Payloadの合計サイズ | |
Variable Header | パケット識別子(Packet Identifier) | 2バイト | 例:0x00 0x0A | 対応するSUBSCRIBEのIDと一致 |
Payload | Return Code(QoSレベル) | 1バイト × トピック数 | 例:0x00, 0x01, 0x02, 0x80 | 各トピックに対する応答。0x80は購読拒否 |
(複数トピックの場合) | 可変 | 例:0x00 0x01 0x80 | SUBSCRIBEで指定した順に並ぶ |
コード | 意味 | 説明 |
---|---|---|
0x00 | QoS 0 | At most once(最低1回) |
0x01 | QoS 1 | At least once(最低1回、重複の可能性あり) |
0x02 | QoS 2 | Exactly once(重複なしで1回) |
0x80 | 失敗 | そのトピックは購読できない |
3.4 PUBLISHパケット
PUBLISHパケットは、クライアントまたはMQTTブローカが「このトピックにメッセージを送ります」と通知するために送るパケットです。
セクション | 項目名 | サイズ | 内容 | 備考 |
---|---|---|---|---|
Fixed Header | パケットタイプ & フラグ | 1バイト | 例:0x30(QoS 0) |
タイプ3(PUBLISH)+フラグ(DUP, QoS, RETAIN) 例:QoS 1なら 0x32、QoS 2なら 0x34 |
残りの長さ(Remaining Length) | 1〜4バイト | 例:0x0F(15バイト) | Variable Header + Payloadの合計サイズ | |
Variable Header | トピック名の長さ | 2バイト | 例:0x00 0x05 | トピック名の文字数 |
トピック名 | Nバイト | 例:`topic` → 0x74 0x6F 0x70 0x69 0x63 | メッセージの送信先 | |
Variable Header(QoS 1以上) | パケット識別子(Packet Identifier) | 2バイト | 例:0x00 0x0A | QoS 1または2のときのみ含まれる |
Payload | メッセージ本体 | 可変 | 例:`Hello` → 0x48 0x65 0x6C 0x6C 0x6F | 送信するデータ |
ビット位置 | 名前 | 値の意味 | 備考 |
---|---|---|---|
7〜4 | Packet Type | 0x3(= PUBLISH) | 常に `0011`(4ビット) |
3 | DUPフラグ | 1 = 再送、0 = 初回送信 | QoS 1または2のときのみ意味を持つ |
2〜1 | QoSレベル | 00 = QoS 0 01 = QoS 1 10 = QoS 2 |
メッセージの配信品質 |
0 | RETAINフラグ | 1 = MQTTブローカに保持させる 0 = 保持しない |
新規購読者にも最後のメッセージを配信 |
3.4.1 PUBACKパケット
PUBACKパケットは、QoS 1で送信されたPUBLISHパケットに対して、MQTTブローカや受信側が「メッセージを受け取りました」と応答するために返すパケットです。
セクション | 項目名 | サイズ | 内容 | 備考 |
---|---|---|---|---|
Fixed Header | パケットタイプ & フラグ | 1バイト | 0x40 | PUBACKはタイプ4、Flagsは0000(固定) |
残りの長さ(Remaining Length) | 1バイト | 0x02 | Variable Headerのサイズ(2バイト) | |
Variable Header | パケット識別子(Packet Identifier) | 2バイト | 例:0x00 0x0A | 対応するPUBLISHのIDと一致 |
Payload | なし | 0バイト | — | PUBACKにはPayloadは存在しない |
3.5 MQTTパケットのシーケンス
MQTTの各パケットのHexペイロードをバイト単位で理解できたと思います。次に実際のパケットの流れを確認します。ここではQoSレベル0の例を以下に示します。QoSレベル0ではPUBACKパケットが発生しない ことに注目してください。
4. SocketDebuggerでの実践
ここからはいよいよ SocketDebuggerを使った手作業でのMQTT通信体験 です。前章で解説した各パケットのバイト構造を意識しながら、実際にパケットを作成して送信してみましょう。
4.1 前提条件
- わかりやすさを優先してシンプルなパケットのやり取りを確認します
- 新規セッション
- 認証・Willなし
- QoS 0
- 今回は無料のインターネット上のMQTTブローカを使用するため、送信するデータは公開されてもよい内容のデータとします
4.2 SocketDebuggerの起動と接続設定
- SocketDebugger① を起動します
- ポート1の通信設定画面で無料のインターネット上のMQTTブローカを指定してTCP接続します
- 通信タイプ:TCPクライアント
- IPアドレス:5.196.78.28 (test.mosquitto.org)
- remoteポート番号:1883
- SocketDebugger② を起動し、上記と同じ設定でMQTTブローカにTCP接続してサブスクライブ受信の準備をします
4.3 SocketDebugger①からMQTTブローカへCONNECTパケット送信
SocketDebugger①の送信データエディタに以下の CONNECTパケット を入力してください。
CONNECTパケット入力後、送信ボタンをクリック すると…
MQTTブローカにCONNECTパケットが送信され、すぐにMQTTブローカから CONNACKパケット が返ってきます!
4.4 SocketDebugger②からMQTTブローカへCONNECTパケット送信
SocketDebugger②の送信データエディタに以下の CONNECTパケット を入力してください。
同様にCONNECTパケット入力後、送信ボタンをクリック すると…
こちらも問題なくMQTTブローカにCONNECTパケットが送信され、すぐにMQTTブローカから CONNACKパケット が返ってきます!
注意
SocketDebugger①、②のそれぞれのクライアントIDはユニークにしてください。(同じクライアントIDで接続すると、MQTTブローカ上で片方の接続が切断されます)
- SocketDebugger①:client1
- SocketDebugger②:client2
4.5 SocketDebugger②からMQTTブローカへSUBSCRIBEパケット送信
SocketDebugger②の送信データエディタに以下の SUBSCRIBEパケット を入力してください。
検証用として、トピックを「udom/topic」とします。
SUBSCRIBEパケット入力後、送信ボタンをクリック すると…
MQTTブローカにSUBSCRIBEパケットが送信され、すぐMQTTブローカから SUBACKパケット が返ってきます!
SUBSCRIBEパケットで指定したパケット識別子になっていることに注目してください。
4.6 SocketDebugger①からMQTTブローカ(→SocketDebugger②)へPUBLISHパケット送信
SocketDebugger①の送信データエディタに以下の PUBLISHパケット を入力してください。
トピックはSUBSCRIBEパケットで指定した「udom/topic」にします。
「udom/topic」宛に送りたいメッセージを「Hello」とします。
PUBLISHパケット入力後、送信ボタンをクリック すると…
SocketDebugger①からMQTTブローカにPUBLISHパケットが送信され、MQTTブローカはそのままPUBLISHパケットをSocketDebugger②へ送信します。 その証拠として SocketDebugger② に PUBLISHパケット が届いています!
また、SocketDebugger①にはPUBLISHパケット送信後にMQTTブローカから PUBACKパケットが届いていない ことが確認できます。これも期待通りです!
5. まとめ
今回は、前回の記事で紹介した MQTTのシンプルな仕組みを理解する概念編 に続き、実際に SocketDebuggerを使って手作業でMQTT通信を行う実践編 を紹介しました。ポイントは以下の通りです。
- MQTTはTCP接続後に、最初に CONNECTパケット を送信することでセッションが確立される
- クライアントIDはMQTTブローカ上で一意である必要があり、同じクライアントIDで新しい接続が確立されると、既存の接続は切断される
- CONNECTの次には、 SUBSCRIBE(購読)や PUBLISH(送信)といった制御パケットを送ることで、実際のメッセージ交換が行える
- SocketDebuggerのようなツールを使うと、TCPレベルのペイロードを直接確認でき、MQTTの仕組みを学習するのに有効
今後は、この記事で得た知識をベースに、SocketDebuggerを使った スクリプトによる自動化 や、QoSやWillメッセージなどの応用的な仕組み にも挑戦していけると、さらに理解が深まるでしょう。
新人研修や自習の一環として、ぜひ今回の内容を実際に試してみてください!👍
禁止事項
本記事では学習用に 無料のMQTTブローカ(test.mosquitto.org) を使用しました。無料MQTTブローカは誰でもアクセスできるため、
- 機密事項や個人情報
- 業務上の重要なデータ
は 絶対に送信しないでください。
実運用では、必ず認証・暗号化を備えた専用のMQTTブローカを利用してください。
6. 付録:無料MQTTブローカ一覧
MQTTサービス名 | URL(サービス説明ページ) | サービスの特徴 | 経路暗号化 |
---|---|---|---|
Mosquitto Test Server | https://test.mosquitto.org/ | 接続検証が主目的のサービス | 選択可 |
EMQX Public MQTT Broker | https://www.emqx.com/ja/mqtt/public-mqtt5-broker | ユーザ登録なしに利用可能な一般公開サービス | 選択可 |
EMQX Serverless MQTT Service | https://www.emqx.com/ja/cloud/serverless-mqtt | ユーザ登録することで、無料の専用サービスとして利用可能 | 必須 |
HiveMQ Free Public MQTT Broker | https://www.hivemq.com/mqtt/public-mqtt-broker/ | ユーザ登録なしに利用可能な一般公開サービス | 選択可 |
HiveMQ Cloud Serverless | https://www.hivemq.com/products/mqtt-cloud-broker/ | ユーザ登録することで、無料の専用サービスとして利用可能 | 必須 |
shiftr.io Public MQTT Broker | https://www.shiftr.io/try | ユーザ登録なしに利用可能な一般公開サービス | 選択可 |
shiftr.io MQTT Cloud Service | https://www.shiftr.io/cloud/ | ユーザ登録することで、無料の専用サービスとして利用可能。ダッシュボードにより接続状況が表示される。 | 選択可 |
MQTT公式仕様
MQTTについて、もっと深く知りたい方は公式の以下のサイトをご参照ください。
本記事のMQTTパケット構造の解説はこちらを参考にして記載しています。
記事リンク
株式会社ユードム
株式会社ユードムはITと人間力で社会に貢献します。
SocketDebuggerのご購入はこちら(期間限定の試用版もあります)
https://www.udom.co.jp/sdg/index.html