MQTTプロトコル分析の概要(1)

関連記事

1.「MQTTプロトコル分析の概要(1)」
2.「MQTTプロトコル分析の概要(2)」
3。「[IoT] BaiduIoTクラウドへの接続方法」
4。「[FreeRTOS] LWIP2.1のSTM32移植に基づくMQTT .2》

1はじめに

MQTT 3(現在のバージョン3.1.1)は現在最も広く使用されていますMQTTプロトコル標準MQTT 5規格がリリースされている、といくつかのエキサイティングな新機能をもたらしていますが、アプリケーション全体のシナリオでは、業界の変遷のバージョンから3への5はしばらく続くことがあります。MQTTの最大の利点は、コードが非常に少なく、帯域幅が限られているリモートデバイスにリアルタイムで信頼性の高いメッセージングサービスを提供できることです。MQTTは、低オーバーヘッド、低帯域幅のインスタントメッセージングプロトコルとして、モノのインターネット、小型デバイス、およびモバイルアプリケーションに幅広いアプリケーションを備えています。

2.MQTTプロトコルの実装方法

MQTTプロトコルを実現するにはクライアントサーバー間の通信を完了する必要があります。通信プロセスでは、MQTTプロトコルにはパブリッシャー(発行)エージェント(ブローカーサーバー)サブスクライバー(サブスクライブ)の3つのIDがありますその中で、メッセージの発行者とサブスクライバーは両方ともクライアントであり、メッセージブローカーはサーバーであり、メッセージ発行者は同時にサブスクライバーになることができます。

MQTTによって送信されるメッセージは、トピックペイロードの2つの部分に分けられます

  • (1)Topic、メッセージのタイプとして理解でき、サブスクライバー订阅(Subscribe)はトピックを受け取ります消息内容(payload);
  • (2)payloadメッセージの内容として理解できます。これは、サブスクライバーが使用したい特定のコンテンツを指します。
    ここに画像の説明を挿入

3.MQTT制御メッセージ形式

MQTTプロトコルTCP作業している場合、エンドとエージェントは事前定義された制御メッセージを交換して通信を完了します。MQTTメッセージは、次の順序で表示される3つの部分で構成されています。

固定ヘッダー 固定ヘッダー、すべての制御メッセージには次のものが含まれます
可変ヘッダー 可変ヘッダー、制御メッセージの一部に含まれる
ペイロード ペイロード、制御メッセージの一部に含まれています

3.1固定ヘッダーのフォーマット

ビット 7 6 5 4 3 2 1 0
バイト1 MQTT制御パケットの種類 制御メッセージのタイプを指定するために使用されるフラグビット
バイト2..。 残りの長さ
  • MQTT制御パケットの種類
ファーストネーム メッセージの流れの方向 説明
予約済み 0 禁止する 保つ
接続する 1 クライアントからサーバーへ クライアントがサーバーへの接続を要求する
コナック 2 サーバーからクライアントへ 接続メッセージの確認
公開 3 両方向が許可されます ニュースリリース
PUBACK 4 両方向が許可されます QoS1メッセージリリースの確認
PUBREC 5 両方向が許可されます リリースして受け取る(確実に配信するための最初のステップ)
PUBREL 6 両方向が許可されます リリースとリリース(保証付き配信の2番目のステップ)
PUBCOMP 7 両方向が許可されます QoS 2ニュースリリースが完了しました(対話の3番目のステップが保証されています)
申し込む 8 クライアントからサーバーへ クライアントサブスクリプションリクエスト
SUBACK 9 サーバーからクライアントへ サブスクリプションリクエストメッセージの確認
購読解除 10 クライアントからサーバーへ クライアントの退会リクエスト
UNSUBACK 11 サーバーからクライアントへ 購読解除メッセージの確認
PINGREQ 12 クライアントからサーバーへ ハートビートリクエスト
PINGRESP 13 サーバーからクライアントへ ハートビート応答
切断 14 クライアントからサーバーへ クライアントが切断されました
予約済み 15 禁止する 保つ
  • 残りの長さの
    位置: 2番目のバイトから始まります。

    残りの長さ(残りの長さ)は、変数ヘッダーペイロードデータを含む、現在のメッセージの残りの部分のバイト数を表します。残りの長さには、残りの長さフィールド自体をエンコードするために使用されるバイト数は含まれません。

    残りの長さフィールドに1つ使用します可変長コーディングスキーム、128未満の値にはシングルバイトエンコーディングを使用します。大きい値は次のように処理されます。下位7ビットはデータのエンコードに使用され、最上位ビットはさらにバイトがあるかどうかを示すために使用されます。したがって、各バイトは128個の値と継続ビットをエンコードできます残りの長さフィールドの最大数は4バイトです。

バイト数 最小 マックス
1 0(0x00) 127(0x7F)
2 128(0x80、0x01) 16 383(0xFF、0x7F)
3 16 384(0x80、0x80、0x01) 2 097 151(0xFF、0xFF、0x7F)
4 2 097 152(0x80、0x80、0x80、0x01) 268 435 455(0xFF、0xFF、0xFF、0x7F)

それぞれ(各バイトの下位7ビットはデータのエンコードに使用され、最上位ビットはフラグビットです):

  • 1バイトの場合、0(0x00)から127(0x7f)
  • 2バイトの場合、128(0x80、0x01)から16383(0Xff、0x7f)
  • 3バイトで、16384(0x80、0x80、0x01)から2097151(0xFF、0xFF、0x7F)
  • 4バイトの場合、2097152(0x80、0x80、0x80、0x01)から268435455(0xFF、0xFF、0xFF、0x7F)

可変長コーディング方式 を使用した非負の整数Xのアルゴリズムは次のとおりです。

   do
  encodedByte = X MOD 128
  X = X DIV 128
 // if there are more data to encode, set the top bit of this byte
 if ( X > 0 )
     encodedByte = encodedByte OR 128
 endif
     'output' encodedByte
while ( X > 0 )

MODはモジュロ演算、DIVは整数除算、ORはビット演算、または(%、/、| C言語)

対応するC言語コードは次のとおりです。

/**
 * Encodes the message length according to the MQTT algorithm
 * @param buf the buffer into which the encoded data is written
 * @param length the length to be encoded
 * @return the number of bytes written to buffer
 */
int MQTTPacket_encode(unsigned char* buf, int length)
{
    
    
	int rc = 0;

	FUNC_ENTRY;
	do
	{
    
    
		char d = length % 128;
		length /= 128;
		/* if there are more digits to encode, set the top bit of this digit */
		if (length > 0)
			d |= 0x80;
		buf[rc++] = d;
	} while (length > 0);
	FUNC_EXIT_RC(rc);
	return rc;
}

残りの長さフィールドの 可変長デコード方式 アルゴリズム次のとおりです。

multiplier = 1
value = 0
do
      encodedByte = 'next byte from stream'
      value += (encodedByte AND 127) * multiplier
      if (multiplier > 128*128*128)
        throw Error(Malformed Remaining Length)
      multiplier *= 128
while ((encodedByte AND 128) != 0)

ANDはビット演算であり、(C言語では&)
このアルゴリズムが終了すると、valueには残りの長さの値が含まれます。

対応するC言語コードは次のとおりです。

/**
 * Decodes the message length according to the MQTT algorithm
 * @param getcharfn pointer to function to read the next character from the data source
 * @param value the decoded length returned
 * @return the number of bytes read from the socket
 */
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
{
    
    
	unsigned char c;
	int multiplier = 1;
	int len = 0;
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4

	FUNC_ENTRY;
	*value = 0;
	do
	{
    
    
		int rc = MQTTPACKET_READ_ERROR;

		if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
		{
    
    
			rc = MQTTPACKET_READ_ERROR;	/* bad data */
			goto exit;
		}
		rc = (*getcharfn)(&c, 1);
		if (rc != 1)
			goto exit;
		*value += (c & 127) * multiplier;
		multiplier *= 128;
	} while ((c & 128) != 0);
exit:
	FUNC_EXIT_RC(len);
	return len;
}

3.2変数ヘッダー

いくつかMQTT制御メッセージ可変ヘッダー部分が含まれています固定ヘッダーとペイロードの間にあります。変数ヘッダーの内容は、メッセージの種類によって異なります。変数ヘッダーのメッセージ識別子(Packet Identifier)フィールドは、複数のタイプのメッセージに存在します。

注:変数ヘッダーはメッセージIDを参照するだけでなく、以下は例としてのみ使用されます。MQTTメッセージタイプが異なれば、変数ヘッダーも異なります。

メッセージ識別子バイトは次のとおりです。

ビット 7 - 0
バイト1 メッセージ識別子MSB
バイト2 メッセージ識別子LSB

多くの制御メッセージの可変ヘッダー部分には、2バイトのメッセージ識別子フィールドが含まれていますメッセージIDを必要とする制御メッセージを次の表に示します。

制御メッセージ メッセージ識別子フィールド
接続する 必要ありません
コナック 必要ありません
公開 必須(QoS> 0の場合)
PUBACK 必要
PUBREC 必要
PUBREL 必要
PUBCOMP 必要
申し込む 必要
SUBACK 必要
購読解除 必要
UNSUBACK 必要
PINGREQ 必要ありません
PINGRESP 必要ありません
切断 必要ありません

クライアントサーバーは、互いに独立してメッセージ識別子を割り当てます。したがって、同じメッセージ識別子を使用するクライアントとサーバーの組み合わせにより、同時メッセージ交換を実現できます。例は次のとおりです。
ここに画像の説明を挿入
ここに画像の説明を挿入

3.3ペイロード

特定のMQTT制御パケットメッセージの最後の部分に含まれるペイロードのために、PUBLISHそれがアプリケーション・メッセージ・ペイロードです。

ペイロードを含む制御パケット

制御メッセージ ペイロード
接続する 必要
コナック 必要ありません
公開 オプション
PUBACK 必要ありません
PUBREC 必要ありません
PUBREL 必要ありません
PUBCOMP 必要ありません
申し込む 必要
SUBACK 必要
購読解除 必要
UNSUBACK 必要ありません
PINGREQ 必要ありません
PINGRESP 必要ありません
切断 必要ありません

4.MQTT制御メッセージ

特定の各メッセージは、次の記事で紹介されています:「MQTTプロトコル分析の概要(2)」

5.参考資料

MQTT 5.0プロトコルの中国語バージョン:
https//github.com/twoFiveOneTen/MQTT_V5
MQTTバージョン5.0:
http//docs.oasis-open.org/mqtt/mqtt/v5.0/cs02/mqtt-v5.0- cs02 .htm
MQTT 3.1.1プロトコル中国語バージョン:
https//github.com/mcxiaoke/mqtt
MQTTバージョン3.1.1:http//docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/
mqtt -v3.1.1-os.html

おすすめ

転載: blog.csdn.net/ZHONGCAI0901/article/details/111600721