Mr.Raindrop

Mr.Raindrop

一切都在无可挽回的走向庸俗。
twitter
github

MQTT3.1.1解析

MQTT プロトコルは実際に長い間使用されており、最近、全体のプロトコルシステムに慣れる機会がありました。主に MQTT3.1.1 プロトコルの中英の紹介文書を参考にしました。

mqtt-v3.1.1-errata01-os-complete.pdf

第 1 章 - MQTT 紹介・MQTT プロトコル日本語版

アプリケーションメッセージ Application Message MQTT プロトコルはネットワークを通じてアプリケーションデータを転送します。アプリケーションメッセージは MQTT を介して転送される際、関連するサービス品質(QoS)とトピック(Topic)があります。

クライアント Client:メッセージを発行し、購読リクエストを行います。

サーバー Server:メッセージを受信し、発行し、購読を処理します。

購読にはトピックフィルター(Topic Filter)と最大サービス品質(QoS)レベルが含まれます。

制御メッセージフォーマット#

MQTT プロトコルは、事前定義された MQTT 制御メッセージを交換することで通信します。

制御メッセージは主に:固定ヘッダー、可変ヘッダー(部分的に含む)、およびペイロード(部分的に含む)を含みます。

制御メッセージタイプ#

名前メッセージの流れの方向説明
Reserved0禁止保留
CONNECT1クライアントからサーバーへクライアントがサーバーへの接続を要求します
CONNACK2サーバーからクライアントへ接続メッセージの確認
PUBLISH3双方向で許可されるメッセージを発行します
PUBACK4双方向で許可されるQoS 1 メッセージの発行が確認されました
PUBREC5双方向で許可される発行を受け取りました(配信保証の第一歩)
PUBREL6双方向で許可される発行を解放します(配信保証の第二歩)
PUBCOMP7双方向で許可されるQoS 2 メッセージの発行が完了しました(配信保証の第三歩)
SUBSCRIBE8クライアントからサーバーへクライアントの購読リクエスト
SUBACK9サーバーからクライアントへ購読リクエストメッセージの確認
UNSUBSCRIBE10クライアントからサーバーへクライアントの購読解除リクエスト
UNSUBACK11サーバーからクライアントへ購読解除メッセージの確認
PINGREQ12クライアントからサーバーへハートビートリクエスト
PINGRESP13サーバーからクライアントへハートビート応答
DISCONNECT14クライアントからサーバーへクライアントが接続を切断します
Reserved15禁止保留

固定ヘッダー#

固定ヘッダーは 2 バイトです。

  • 最初のバイト:上位 4 ビットは制御メッセージタイプで、下位 4 ビットは対応する制御メッセージタイプのフラグビットです
  • 2 番目のバイト(残りの長さ):現在のメッセージの残り部分のバイト数を示します。可変ヘッダーとペイロードのデータを含みます。残りの長さは、残りの長さフィールド自体のエンコーディングに使用されるバイト数を含みません。

可変ヘッダー#

固定ヘッダーとペイロードの間に位置します。多くの制御メッセージの可変ヘッダー部分には2 バイトのメッセージ識別子フィールドが含まれます

有効ペイロード#

メッセージの最後に位置します。

MQTT の実行フロー#

クライアント接続#

クライアントがサーバーに connect メッセージを送信します

クライアント識別子(必須)、ユーザー名、パスワード、プロトコルレベル、および遺言情報などを含みます。

サーバーがクライアントに CONNACK で接続リクエストを確認します

トピックの購読#

クライアントがサーバーに SUBSCRIBE メッセージを送信して1 つ以上の購読を作成します(ワイルドカードをサポート)。SUBSCRIBE メッセージは(各購読のために)最大 QoS レベルを指定します、サーバーはこれに基づいてアプリケーションメッセージをクライアントに送信します。

SUBACK は購読確認に使用されます。<font style="color:rgb(0, 0, 0);">SUBACK</font>メッセージは<font style="color:rgb(0, 0, 0);">SUBSCRIBE</font>メッセージの各トピックフィルターに対して付与された QoS レベルを返します(このレベルはクライアントが要求した最大 QoS と等しいか小さい可能性がありますが、それを超えることはありません)。

PUBLISH メッセージの送信#

クライアントは PUBLISH メッセージを使用してアプリケーションメッセージをサーバーに送信し、目的は他の購読者に配信することです

サーバーは PUBLISH メッセージを使用して各購読者にアプリケーションメッセージを送信します

可変ヘッダーにはトピック名とメッセージ識別子が含まれ、ペイロードには発行されるメッセージが含まれます。

  • QoS が 0 の場合、確認プロセスはありません。
  • QoS が 1 の場合、PUBACK による発行確認が必要です。
  • QoS が 2 の場合、最初に PUBREC による発行受信確認を行い、その後 PUBREL による発行解放確認を行い、最後に PUBCOMP による発行完了確認を行います。

購読解除#

UNSUBSCRIBE を使用して購読を解除します。

UNSUBACK を使用して UNSUBSCRIBE メッセージを受信したことを確認します。

接続の切断#

クライアントが DISCONNECT メッセージを送信し、サーバーとの接続を切断します。

制御メッセージ#

CONNECT – サーバーへの接続#

  • クライアントからサーバーへのネットワーク接続が確立された後、クライアントがサーバーに送信する最初のメッセージは必ずCONNECT メッセージでなければなりません
  • 1 つのネットワーク接続上で、クライアントは CONNECT メッセージを 1 回だけ送信できます。
  • ペイロードには 1 つ以上のエンコードされたフィールドが含まれます。クライアントの一意の識別子、Will トピック、Will メッセージ、ユーザー名、パスワードが含まれます。

固定ヘッダー#

最初のバイト:メッセージタイプ 0001 下位 4 ビットは保留ビットとして使用されます。

残りの長さは可変ヘッダーの長さ(10 バイト)とペイロードの長さの合計です。

可変ヘッダー#

CONNECT メッセージの可変ヘッダーは、次の順序で 4 つのフィールドを含みます:プロトコル名(Protocol Name)、プロトコルレベル(Protocol Level)、接続フラグ(Connect Flags)、およびキープアライブ(Keep Alive)。

プロトコル名:MQTT のエンコーディングを示します#

プロトコルレベル:プロトコルのバージョンを示します#

接続フラグ Connect Flags#

image

  • クリーンセッション Clean Session

0 の場合:サーバーは現在のセッション(クライアント識別子で識別)に基づいてクライアントとの通信を復元する必要があります。

1 の場合:切断後、古いセッションは破棄されます。

接続切断中のメッセージを失わないようにするには、QoS 1 または QoS 2 レベルを使用し、クリーンセッションフラグを 0 に設定する必要があります。

  • ** 遺言フラグ:** サーバーが遺言メッセージを発行する必要があるかどうか
  • ** 遺言 QoS:** 遺言メッセージの QoS レベル
  • ** 遺言保持:** 遺言メッセージを保持メッセージとして発行するかどうか
  • ** ユーザー名フラグ:** ペイロードにユーザー名が含まれているかどうか
  • ** パスワードフラグ:** ペイロードにパスワードが含まれているかどうか

キープアライブ#

キープアライブ(Keep Alive)は秒単位の時間間隔です。

これは、クライアントが 1 つの制御メッセージを送信した時点から次のメッセージを送信する時点までの間の最大のアイドル時間を示します。この間に他の制御メッセージを送信できない場合、クライアントはPINGREQ メッセージを送信しなければなりません

キープアライブの値がゼロでなく、サーバーが 1.5 倍のキープアライブ時間内にクライアントの制御メッセージを受信しなかった場合、クライアントのネットワーク接続を切断しなければなりません、ネットワーク接続が切断されたと見なされます。

クライアントが PINGREQ メッセージを送信した後、合理的な時間内に PINGRESP メッセージを受信しなかった場合、**サーバーへのネットワーク接続を閉じるべきです。

キープアライブの値がゼロであることは、キープアライブ機能を無効にすることを示します。

ペイロード#

CONNECT メッセージのペイロード(payload)には、長さを前置きしたフィールドが 1 つ以上含まれます。可変ヘッダーのフラグがこれらのフィールドを含むかどうかを決定します。含まれる場合、**この順序で出現する必要があります:クライアント識別子、遺言トピック、遺言メッセージ、ユーザー名、パスワード。

クライアント識別子#

サーバーはクライアント識別子(ClientId)を使用してクライアントを識別します。サーバーに接続する各クライアントには一意のクライアント識別子(ClientId)が必要です。クライアントとサーバーは、ClientId を使用して MQTT セッションに関連する状態を識別する必要があります。

クライアント識別子(ClientId) は必ず存在し、CONNECT メッセージのペイロードの最初のフィールドでなければなりません。

遺言トピック#

遺言フラグが 1 に設定されている場合、ペイロードの次のフィールドは遺言トピック(Will Topic)です。次に遺言メッセージが続き、フラグに応じてユーザー名とパスワードが含まれます。

応答#

サーバーは同じ TCP ポートまたは他のネットワークエンドポイントで複数のプロトコルをサポートできます。

サーバーは、CONNECT メッセージの確認応答として、戻りコードがゼロの CONNACK メッセージを送信する必要があります。ただし、クライアントは CONNACK を受信する前に制御メッセージを送信できます。

CONNACK – 接続リクエストの確認#

サーバーは、クライアントから受信した CONNECT メッセージに応じて CONNACK メッセージを送信します。サーバーがクライアントに送信する最初のメッセージは必ず CONNACK でなければなりません。

固定ヘッダー#

image

可変ヘッダー#

接続確認フラグ#

第 0 (SP) ビットは現在のセッション(Session Present)フラグです。その他(1-7)ビットは 0 である必要があります。

サーバーがクリーンセッション(CleanSession)フラグが 1 の接続を受信した場合、CONNACK メッセージの戻りコードを 0 に設定するだけでなく、CONNACK メッセージの現在のセッション設定(Session Present)フラグも 0 に設定する必要があります。

サーバーが CleanSession が 0 の接続リクエストを受信した場合、クライアント(ClientId で識別)のセッション情報が保存されているかどうかに基づいて CONNACK 応答の現在のセッションフラグを決定する必要があります。以前にこのクライアントのセッション情報が保存されていた場合、CONNACK で現在のセッションフラグを 1 に設定します。保存されていない場合は 0 に設定します。また、どちらの場合でも、CONNACK の戻りコードが 0 であることを確認する必要があります。

接続戻りコード#

無符号値で、0 は正常接続を示し、非 0 値は接続が拒否されたことを示します。

有効ペイロードなし#

Publish - メッセージの発行#

固定ヘッダー#

image

再送信フラグ DUP: 0 初回リクエスト送信,1 再送信メッセージを示します。#

送信(アウトバウンド)の PUBLISH メッセージと受信(インバウンド)の PUBLISH メッセージの DUP フラグは独立して設定され、送信(アウトバウンド)の PUBLISH メッセージが再送信であるかどうかに基づいてその値を決定する必要があります。

サービス品質レベル QOS#

image

保持フラグ RETAIN#

クライアントがサーバーに送信する PUBLISH メッセージの保持(RETAIN)フラグが 1 に設定されている場合、サーバーはこのアプリケーションメッセージとそのサービス品質レベル(QoS)を保存し、将来のトピック名に一致する購読者に配信できるようにする必要があります。

新しい購読が確立されると、各一致するトピック名について、最近保持されたメッセージが存在する場合、それをこの購読者に送信する必要があります。

サーバーが保持(RETAIN)フラグが 1 の QoS 0 メッセージを受信した場合、そのトピックに対して以前に保持されていたメッセージを破棄する必要があります。この新しい QoS 0 メッセージをそのトピックの新しい保持メッセージとして扱う必要がありますが、いつでも破棄することを選択できます。この場合、そのトピックには保持メッセージがなくなります。

サーバーがクライアントへの PUBLISH メッセージを送信する際、メッセージがクライアントの新しい購読の結果として送信される場合、メッセージの保持フラグを 1 に設定する必要があります。

残りの長さフィールド#

可変ヘッダーの長さとペイロードの長さの合計です。

可変ヘッダー#

トピック名とメッセージ識別子を含みます。

トピック名#

可変ヘッダーの最初のフィールドです。

トピック名にはワイルドカードを含めることはできません。

メッセージ識別子#

QoS が 1 または 2 の場合に存在します。

有効ペイロード#

有効ペイロードには発行されるアプリケーションメッセージが含まれます。データの内容と形式はアプリケーション固有です。

応答#

受信者と発行者の QoS レベルは同じである必要があります。

アクション#

クライアントは PUBLISH メッセージを使用してアプリケーションメッセージをサーバーに送信し、目的は他の購読者に配信することです

サーバーは PUBLISH メッセージを使用して各購読者にアプリケーションメッセージを送信します

クライアントがワイルドカードを含むトピックフィルターを使用して購読をリクエストする場合、クライアントの購読は重複する可能性があるため、発行されたメッセージは複数のフィルターに一致する可能性があります。この場合、サーバーはメッセージをすべての購読者に QoS レベルが最も高いものに配信する必要があります

その後、サーバーは購読の QoS レベルに従って、各一致する購読者にメッセージのコピーを配信できます。

PUBACK – 発行確認#

QoS 1 レベルの PUBLISH メッセージの応答です。

固定ヘッダー#

MQTT メッセージ制御タイプは 4 です。

残りの長さフィールドは 2 です。

可変ヘッダー#

確認を待っている PUBLISH メッセージのメッセージ識別子を含みます。

有効ペイロードなし#

PUBREC – 発行受信(QoS 2、第一歩)#

QoS レベル 2 の PUBLISH メッセージの応答です。これは QoS 2 レベルプロトコル交換の第二のメッセージです。

固定ヘッダー
MQTT メッセージ制御タイプは 5 です
残りの長さフィールドは 2 です

可変ヘッダー#

確認を待っている PUBLISH メッセージのメッセージ識別子を含みます。

有効ペイロードなし

PUBREL – 発行解放(QoS 2、第二歩) #

PUBREC メッセージへの応答です。これは QoS 2 レベルプロトコル交換の第三のメッセージです。

固定ヘッダー#

MQTT メッセージ制御タイプは 5 です

残りの長さフィールドは 2 です

可変ヘッダー#

確認を待っている PUBREC メッセージと同じメッセージ識別子です。

有効ペイロードなし

PUBCOMP – 発行完了(QoS 2、第三歩) #

PUBREL メッセージへの応答です。これは QoS 2 レベルプロトコル交換の第四のメッセージであり、最後のメッセージです。

固定ヘッダー
MQTT メッセージ制御タイプは 7 です
残りの長さフィールドは 2 です
可変ヘッダー

確認を待っている PUBREC メッセージと同じメッセージ識別子です。
有効ペイロードなし

SUBSCRIBE - トピックの購読 #

クライアントがサーバーに SUBSCRIBE メッセージを送信して1 つ以上の購読を作成します。SUBSCRIBE メッセージは **(各購読のために)最大 QoS レベルを指定します **、サーバーはこれに基づいてアプリケーションメッセージをクライアントに送信します。

固定ヘッダー
MQTT メッセージ制御タイプは 5 です
残りの長さフィールドは可変ヘッダー + 有効ペイロードの長さです

可変ヘッダー#

可変ヘッダーにはクライアント識別子が含まれます。

有効ペイロード#

トピックフィルターと QoS レベルフィールドの組み合わせ

クライアントが購読したいトピックを示します。 サーバーは ** ワイルドカードを含むトピックフィルターをサポートする必要があります(4.7.1 節で定義されています)。** サーバーがワイルドカードを含むトピックフィルターをサポートしないことを選択した場合、ワイルドカードフィルターを含む購読リクエストを拒否しなければなりません。

各フィルターの後には 1 バイトが続き、このバイトはサービス品質要求(Requested QoS)と呼ばれます。これは、サーバーがクライアントにアプリケーションメッセージを送信する際に許可される最大 QoS レベルを示します。有効ペイロードには、少なくとも 1 対のトピックフィルターと QoS レベルフィールドの組み合わせが含まれている必要があります。

有効ペイロードなしの SUBSCRIBE メッセージはプロトコル違反です。

応答#

サーバーがクライアントから送信された SUBSCRIBE メッセージを受信した場合、SUBACK メッセージで応答する必要があります。SUBACK メッセージは、確認を待っている SUBSCRIBE メッセージと同じメッセージ識別子を持たなければなりません。

新しい購読のトピックフィルターは以前の購読と同じですが、最大 QoS 値は異なる場合があります。このトピックフィルターに一致する既存の保持メッセージは再送信される必要がありますが、発行プロセスは中断されてはなりません。

サーバーが複数のトピックフィルターを含む SUBSCRIBE メッセージを受信した場合、それを一連の複数の SUBSCRIBE メッセージを受信したかのように処理する必要がありますが、それらの応答を 1 つの SUBACK メッセージに統合して送信する必要があります。SUBACK 応答は統合できます

SUBACK メッセージは、各トピックフィルターと QoS レベルのペアに対して戻りコードを含む必要があります。

サーバーは、購読者が要求したよりも低い QoS レベルを付与することができます。購読に応じて送信されるメッセージの有効ペイロードの QoS は、元の発行メッセージの QoS とサーバーが付与した QoS の両方の最小値でなければなりません。

メッセージ配信時の最大 QoS レベルを決定するのは発行者の責任であり、購読者はサーバーに QoS をより適切なレベルに引き下げるよう要求できます。

SUBACK – 購読確認#

SUBSCRIBE メッセージを受信し、処理中であることを確認するために使用されます。最大 QoS レベルが指定された各購読に対して戻りコードのリストを含みます。

固定ヘッダー

MQTT メッセージ制御タイプは 5 です

残りの長さフィールドは可変ヘッダー + 有効ペイロードの長さです

可変ヘッダー#

確認を待っている SUBSCRIBE メッセージのメッセージ識別子を含みます。

有効ペイロード#

戻りコードのリストを含みます。各戻りコードは、確認を待っている SUBSCRIBE メッセージのトピックフィルターに対応します。戻りコードの順序は、SUBSCRIBE メッセージのトピックフィルターの順序と同じでなければなりません。

許可される戻りコード値:

0x00 - 最大 QoS 0

0x01 - 成功 – 最大 QoS 1

0x02 - 成功 – 最大 QoS 2

0x80 - 失敗

UNSUBSCRIBE – 購読解除#

トピックの購読を解除するために使用されます。

固定ヘッダー#

制御メッセージタイプ 10

保留ビット 0、0、1、0

** 残りの長さフィールド **可変ヘッダー + 有効ペイロードの長さ

可変ヘッダー#

有効ペイロード#

クライアントが購読解除したいトピックのリストを含みます。

応答#

サーバーが購読を削除した場合:

  • そのクライアントに新しいメッセージを配信するのを停止します
  • QoS 1 および QoS 2 のメッセージをクライアントに送信するために開始された配信を完了します
  • クライアントに配信するために準備された既存のメッセージを引き続き送信します。

サーバーは、クライアントの UNSUBSCRIBE リクエストに応じて UNSUBACK メッセージを送信する必要があります。

UNSUBACK – 購読解除確認#

UNSUBSCRIBE メッセージを受信したことを確認するために使用されます。

固定ヘッダー#

制御メッセージタイプ 11

残りの長さ 2

可変ヘッダー#

有効ペイロード#

有効ペイロードなし

PINGREQ – ハートビートリクエスト#

  • サーバーにクライアントがまだ生きていることを知らせます。
  • サーバーに応答を送信して生きていることを確認するように要求します。
  • ネットワーク接続が切断されていないことを確認するためにネットワークを使用します。

固定ヘッダー#

制御メッセージタイプ 12

残りの長さ 0

可変ヘッダーおよび有効ペイロードなし

応答#

サーバーは、クライアントの PINGREQ メッセージに応じて PINGRESP メッセージを送信する必要があります。

PINGRESP – ハートビート応答#

クライアントの PINGREQ メッセージに応じて PINGRESP メッセージを送信します。サーバーがまだ生きていることを示します。

固定ヘッダー#

制御メッセージタイプ 13

残りの長さ 0
可変ヘッダーおよび有効ペイロードなし

DISCONNECT – 接続の切断 #

制御メッセージタイプ 14

保留ビット 0

残りの長さ 0 可変ヘッダーおよび有効ペイロードなし

応答 #

クライアントが DISCONNECT メッセージを送信した後:

  • ネットワーク接続を閉じる必要があります
  • そのネットワーク接続を通じて他の制御メッセージを送信してはなりません

サーバーが DISCONNECT メッセージを受信した場合:

  • 現在の接続に関連する未発行の遺言メッセージを破棄する必要があります
  • クライアントがまだ行っていない場合、ネットワーク接続を閉じるべきです。

操作行動#

MQTT 3.1 で使用されるトランスポート層プロトコルは、[RFC793] で定義された TCP/IP プロトコルです。同時に TLS、WebSocket プロトコルもサポートしています。

サービス品質レベルとプロトコルフロー#

QoS 0: 最多 1 回配信#

メッセージの配信は、基盤となるネットワークの能力に依存します。受信者は応答を送信せず、送信者も再試行しません。

QoS 1: 少なくとも 1 回配信#

QoS 1 の PUBLISH メッセージの可変ヘッダーにはメッセージ識別子が含まれ、PUBACK メッセージによる確認が必要です。

送信者:

  • 新しいアプリケーションメッセージを送信するたびに、未使用のメッセージ識別子を割り当てる必要があります。

  • 送信された PUBLISH メッセージにはメッセージ識別子が含まれ、QoS は 1 で、DUP は 0 である必要があります。

  • この PUBLISH メッセージは未確認と見なされ、受信者から対応する PUBACK メッセージを受信するまで確認されません。

受信者:

  • 応答の PUBACK メッセージにはメッセージ識別子が含まれている必要があります。この識別子は、受信した PUBLISH メッセージからのもので、すべての権利を受け入れたものです。

  • PUBACK メッセージを送信した後、受信者は同じメッセージ識別子を持つ入ってくる PUBLISH メッセージを新しいメッセージとして扱い、DUP フラグの値を無視する必要があります。

QoS 2: 1 回のみ配信#

メッセージの損失や重複は許容されません。

送信者:

  • 送信する新しいアプリケーションメッセージに未使用のメッセージ識別子を割り当てる必要があります。
  • 送信された PUBLISH メッセージにはメッセージ識別子が含まれ、メッセージの QoS は 2 で、DUP は 0 である必要があります。
  • この PUBLISH メッセージは未確認と見なされ、受信者から対応する PUBREC メッセージを受信するまで確認されません。
  • PUBREC メッセージを受信した後、PUBREL メッセージを送信する必要があります。PUBREL メッセージには元の PUBLISH メッセージと同じメッセージ識別子が含まれなければなりません。
  • この PUBREL メッセージは未確認と見なされ、受信者から対応する PUBCOMP メッセージを受信するまで確認されません。
  • 対応する PUBREL メッセージを送信した後は、この PUBLISH メッセージを再送信してはなりません。

応答者:

  • 応答の PUBREC メッセージにはメッセージ識別子が含まれている必要があります。この識別子は、受信した PUBLISH メッセージからのもので、すべての権利を受け入れたものです。
  • 対応する PUBREL メッセージを受信するまで、受信者は同じ識別子を持つ後続の PUBLISH メッセージを PUBREC メッセージで確認する必要があります。この場合、後続の受信者にメッセージを再配信してはなりません。
  • PUBREL メッセージに応答する PUBCOMP メッセージには、PUBREL メッセージと同じ識別子が含まれなければなりません。
  • PUBCOMP メッセージを送信した後、受信者は同じメッセージ識別子を持つ後続の PUBLISH メッセージを新しい発行として扱う必要があります。

メッセージ配信の再試行#

クライアントとサーバーは、元のメッセージ識別子を使用して、未確認の PUBLISH メッセージ(QoS>0 の場合)および PUBREL メッセージを再送信する必要があります。これは、クライアントまたはサーバーがメッセージを再送信する唯一の要求です。

トピック名とトピックフィルター#

トピックワイルドカード#

スラッシュ(‘/’ U+002F)は、トピックの各レベルを分割するために使用され、トピック名に階層構造を提供します。

多層ワイルドカード#

数字記号(‘#’ U+0023)は、トピック内の任意のレベルに一致するためのワイルドカードです。

単層ワイルドカード#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。