MQTTナレッジポイント

1.MQTTの概要

1はじめに

MQTT(メッセージキューテレメトリトランスポート)は、IBMによって開発されたインスタントメッセージングプロトコルです。これは、ネットワークに制約のあるデバイス、低帯域幅、高遅延で信頼性の低いネットワーク向けに設計された非常に軽量なパブリッシュ/サブスクライブメッセージングプロトコルです。上記の軽量特性により、スマートホームの実装に適した伝送プロトコルです。XMPPと比較して、軽量で低帯域幅を使用します。

 MQTT官0042:http://mqtt.org/
 MQTT介绍:http://www.ibm.com
 MQTT Android github:https://github.com/eclipse/paho.mqtt.android
 MQTT API:http:// www .eclipse.org / paho / files / javadoc / index.html
 MQTT Android API:http://www.eclipse.org/paho/files/android-javadoc/index.html

2.機能

a。パブリッシュ/サブスクライブメッセージモードを使用しているため、1対多のメッセージパブリッシングを提供できます
。b。軽量でネットワークオーバーヘッドが少ない
c。ロードコンテンツをシールドしたメッセージ送信
d。3つのメッセージパブリッシング品質(Qos)があります。 :
= 0のQoS:「一度だけ」、メッセージの損失や重複がこのレベルで発生するメッセージ・パブリッシングは、TCP / IPネットワークに依存
= 1のQoS:メッセージが到着することを保証するが、メッセージの重複する「少なくとも一度」かもしれません発生
qos = 2:「1回のみ」、メッセージが1回到着するようにする
e。通知メカニズム、異常な中断が発生したときに両方の当事者に通知されます

3.原則

14523188625918865.png

 

MQTTプロトコルには、パブリッシャー、ブローカー、サブスクライバーの3つのIDがあります。パブリッシャーとサブスクライバーは両方ともクライアントであり、プロキシはサーバーです。同時に、メッセージのパブリッシャーはサブスクライバーになることもできます(メモリとトラフィックを節約するために、パブリッシャーとサブスクライバーは通常、一緒に定義されます)。
MQTTによって送信されるメッセージは、トピック(トピック、メッセージのタイプとして理解できます。サブスクライバーがサブスクライブした後、トピックのメッセージコンテンツ(ペイロード)を受信します)とペイロード(ペイロード、メッセージの内容として理解されます)。

2.MQTTの一般的な使用

依存関係を追加する

リポジトリ{     maven {         url "https://repo.eclipse.org/content/repositories/paho-releases/"     } }



依存関係{     コンパイル 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'     コンパイル 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.0' }


制限を追加

    <uses-permission android:name = "android.permission.INTERNET" />
    <uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name = "android.permission.WAKE_LOCK" / >>

登録サービス

        <!-Mqttサービス->
        <service android:name = "org.eclipse.paho.android.service.MqttService" />
        <service android:name = "com.dongyk.service.MQTTService" />

 

QoS(Quality of Service)
は、メッセージ送信のサービス品質を指します。次のレベルが含まれます。

サービスの質 具体的な意味
QoS0 最大で1回配布
QoS1 少なくとも1回は意味します
QoS2 デリゲートは1回だけ配布します

cleanSession
cleanSessionフラグは、MQTTプロトコルでTCP接続を確立した後、クライアントが前の状態を気にするかどうかの定義です。具体的なセマンティクスは次のとおりです。

cleanSession 具体的な意味
true 非持続的接続。クライアントが再びオンラインになると、以前のすべてのサブスクリプション関係とオフラインメッセージを気にする必要がなくなります。
false 持続的接続、クライアントが再びオンラインになると、以前のオフラインメッセージを処理する必要があり、以前のサブスクリプション関係は引き続き有効になります

QoSとcleanSessionのさまざまな組み合わせの結果を次の表に示します。

QoSレベル cleanSession = true cleanSession = false
QoS0 オフラインメッセージはありません。オンラインメッセージは一度だけプッシュしようとします オフラインメッセージはありません。オンラインメッセージは一度だけプッシュしようとします
QoS1 オフラインメッセージはありません。オンラインメッセージは到達可能であることが保証されています オフラインメッセージがあり、すべてのメッセージが到達可能であることが保証されています
QoS2 オフラインメッセージはありません。オンラインメッセージは1回だけ投稿されることが保証されています オフラインメッセージがあり、すべてのメッセージは一度だけプッシュされることが保証されています

QoS> 0のメッセージの場合、持続的接続の場合、クライアントがオフラインのとき、メッセージはブローカーに送信されます。クライアントがオンラインのとき、mqttはブローカーからメッセージをプルし、クライアントにプッシュします。 。

 

Mqttクライアントマルチトピックサブスクリプション

mqttのトピックは階層的な概念です。複数のトピックをサブスクライブする場合は、このテクニカルポイントを使用する必要があります。
機能は、トピックに階層を導入することです。レベルは、トピックレベルの区切り文字、マルチレベルのワイルドカード、およびシングルレベルのワイルドカードに分けられます
。これらのレベルは、メッセージを公開するための公開インターフェイスでは使用できないことに注意してください。
レベルの分類
トピックレベルの区切り記号:/
マルチレベルのワイルドカード: #
単一レベルのワイルドカード:+

トピックレベルの区切り文字
「/」は、トピックツリーの各レベルを分離し、トピックスペースの階層構造を提供するために使用されます。サブジェクトに2つのワイルドカードが表示される場合、サブジェクトレベルの区切り文字を使用することが非常に重要です。
//件名トピック1:3つのレベルに分割/ test / child / aaa //トピック2:4つのレベルに分割/ test / child / aaa2 / bbb2
マルチレイヤーワイルドカード
マルチレイヤーワイルドカード「#」は、任意の数のレベルに一致しますトピックワイルドカードで。ケースを使用して
ケース1を説明しましょう
トピックをサブスクライブします:/ test / child /#
次のトピックからメッセージを受信します:
/ test / child / test / child / aaa / test / child / ccc / test / child / aaa / bbb / test / child / aaa / bbb / ddd

マルチレベルワイルドカードは、0以上のレベルとして理解できます。
マルチレベルワイルドカードは、現在のレベルまたは次のレベルのみを判別できます

一般的なエラーと正しい表示ケース
#//成功、/で始まらないすべてのトピックが受信されます/#//成功/テスト/#/子//エラー、#最後の文字である必要があります/テスト/#//成功/ test / child#//エラー無効なワイルドカード/ test / child /#//成功
シングルレベルワイルドカード
シングルレベルワイルドカード "+"は、トピックの1つのレベルにのみ一致します
ケース1トピックを
サブスクライブします:/ test / child / +
これらを受信します件名から送信されたメッセージ:注:/ test / child件名
/ test / child / aaa / test / child / bbb / test / child / cccから送信されたメッセージを受信できません
一般的なエラーと正しい表示ケース
+ //成功/ + / /成功/テスト/ + /子供//成功、/テスト/ + //成功/テスト/子+ //エラー、無効なワイルドカード/テスト/子供/ + //成功
テーマの構文と使用
するときアプリケーションを構築し、テーマを設計するツリー化するときは、トピック名の次の構文とセマンティクスを考慮する必要があります
。トピックは少なくとも1文字の長さです。
件名では大文字と小文字が区別されます。たとえば、ACCOUNTSとAccountsは2つの異なるトピックです。
件名にはスペースを含めることができます。たとえば、買掛金は効果的な対象です。
/で始まると、別のテーマが生成されます。たとえば、/ finnaceはfinanceとは異なります。/ financeは "+ / +"と/ +に一致しますが、一致しません+
どの件名にもnull(Unicode \ x0000)文字を含めないでください。トピックツリー
の構成と内容には
次の原則が適用されます。トピックツリーでは、長さは64kに制限されていますが、この中のレベルの数に制限はありません。
ルートノードはいくつあってもかまいません。つまり、トピックツリーはいくつあってもかまいません。

 

 

 

 

 

 

 


————————————————

Mqttクライアントマルチトピックサブスクリプション:https://blog.csdn.net/qq_22889431/article/details/105321843

mqttオフラインメッセージの実現:https://www.jianshu.com/p/e85cdaae65bd

 

mqttは、非常に軽量な公開/サブスクライブメッセージングプロトコル(制限されたデバイスおよび低帯域幅、高遅延、または信頼性の低いネットワーク向けに設計)であり、コードサイズが小さく、消費電力が少ないため、モバイルデバイス、車両に適しています。ネットワーク信号が不安定な場合(弱いネットワーク、切断されている、トンネル内にネットワークがないなど)、ネットワークが後で復元されると、メッセージの送受信を続行でき、以前のオフラインメッセージを受信できます。補足プッシュ。オフラインメッセージの補足プッシュもIMサーバー自体で制御できますが、Mqttプロトコルがオフラインプッシュをネイティブにサポートしている場合、州の開発者がそれを自分で処理することを意味するのではありません。同時に、古いものではなく新しいものを使用するという見方に固執し、Mqtt3ではなくMqtt5を決定的に選択します。Mqtt3と比較して、Mqtt5には、理由コード(PUBACK / PUBREC)、共有サブスクリプション、セッションの有効期限など、多くのアップグレードがあります。 、要求/応答モード(ResponseTopic、CorrelationData)、WillDelayなど。
Mqttのサーバーとクライアントの選択については、次のリンクを参照してください
。Mqtt公式ウェブサイト
Mqtt中国のウェブサイト
Mqttサーバー側
Mqttクライアント側
実際の開発プロセスでは、サーバー側がEmqを選択し、クライアント側がHiveMqを選択し、どちらもMqtt5をサポートします。
Mqtt5オフラインメッセージ受信のためのいくつかのコアの設定をサポートしてい
ClientIdを
CleanStart:偽
SessionExpiry
のQoS:2
CONNACKにセッション存在フラグ
ClientIdを一意ユーザセッションを識別するために使用されます。
CleanStartは0に設定されます。これは、永続セッションが作成されることを意味します。クライアントが切断されると、セッションは残り、セッションがタイムアウトしてログアウトするまでオフラインメッセージを保存します。CleanStartは1に設定されています。これは、新しい一時セッションが作成されることを意味します。クライアントが切断されると、セッションは自動的に破棄されます。
SessionExpiryは、CleanStartが0のときにセッションが保存される期間を指定します。クライアントがユーザー定義の期間内に接続しない場合、クリーンアップせずに状態(サブスクリプションやバッファリングされたメッセージなど)を破棄できます。
Qosはメッセージのサービス品質です。オフラインメッセージをサポートする場合は、サブスクライブしてパブリッシュする必要があります。Qos> = 1
セッション存在は、セッション存在識別子がmqttへの接続のConnAck戻り結果に含まれることを意味します。サーバー。現在のclientIdが存在するかどうかを示します。前の永続セッション(永続セッション)、前にセッションがある場合(この時点でトピックに再サブスクライブしないでください。再度サブスクライブすると、前のメッセージは受信されません)、セッションは、オフライン(Qos> = 1)の場合、以前のサブスクリプション関係とクライアントメッセージを保持します。重要な点は、存在するセッションの使用法を説明することです。クライアントがmqttサーバーに接続し、コナックでisSessionPresent識別子を取得するとき、isSessionPresent = trueの場合、セッションはすでに存在し、トピックを繰り返しサブスクライブする必要はありません。 (サブスクリプション関係はセッションに保存されています。サブスクリプションを再度繰り返すと、以前のオフラインメッセージは受信されません)、後でグローバル受信を介してオフラインメッセージと新しいメッセージを処理できます。isSessionPresent= falseの場合、セッションはありません。 (またはセッションの有効期限が切れている)、この時点でトピックを再サブスクライブする必要があります。以前はオフラインメッセージを受信して​​おらず、オフラインメッセージは他の方法(たとえば、IMの完全同期サービス)でのみ取得できます。バックエンドサービス)。

たとえば、ClientId = 1、CleanStart = false、SessionExpiry = 3600s、Qos = 2は、clientId = 1のセッションが永続セッションとして指定されていることを意味します。ユーザーがオフラインになった後の3600秒のオフラインメッセージは、Mqttサーバーによって保存されます。ユーザーのオフライン時間が3600秒を超えず、ClientId = 1で再びオンラインになると、オフライン期間中にメッセージの補足プッシュを受信でき、Qos = 2(正確に1回)はメッセージが受信されることのみを保証しますクライアントによって一度だけ。
例としてHiveMqクライアントコードを取り上げます。
注:asyncClient.publishesのグローバルメッセージ受信は、connectメソッド呼び出し
パッケージcom.mx.mqtt.sysの前に配置する必要があります

インポートcom.hivemq.client.mqtt.MqttGlobalPublishFilter;
インポートcom.hivemq.client.mqtt.datatypes.MqttQos;
インポートcom.hivemq.client.mqtt.lifecycle.MqttClientConnectedContext;
インポートcom.hivemq.client.mqtt.lifecycle.MqttClientConnectedListener;
インポートcom.hivemq.client.mqtt.lifecycle.MqttClientDisconnectedContext;
インポートcom.hivemq.client.mqtt.lifecycle.MqttClientDisconnectedListener;
インポートcom.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient;
インポートcom.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient;
インポートcom.hivemq.client.mqtt.mqtt5.Mqtt5Client;
インポートcom.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5ConnAckException;
インポートcom.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5SimpleAuth;
インポートcom.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck;
インポートcom.mx.mqtt.jwt.JwtUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

インポートjava.io.UnsupportedEncodingException;

/ **
 * emqx -セッション
 *
 * @Ahthor luohq
 * @Date 2020年4月9日
 * /
パブリッククラスEmqxOfflineClient {

    /
     ***日志
     * /
    private static final Logger logger = LogManager.getLogger(EmqxOfflineClient.class);


    プライベート静的最終文字列MQTT_JWT_SECRET = "xxxx";
    プライベート静的最終文字列MQTT_SERVER_HOST = "192.168.xxx.xxx";
    プライベート静的最終整数MQTT_SERVER_PORT = 1883;
    private static final String MQTT_CLIENT_ID = "luohq-offline";
    public static final String MQTT_SUB_TOPIC = "luohq / offset";
    public static final Long SESSION_EXPIRATION = 5 * 60L;


    プライベート静的ブールisSessionPresent = false;
    プライベート静的Mqtt5BlockingClientクライアント。
    プライベート静的Mqtt5AsyncClientasyncClient;


    public static void main(String [] args){         / **ビルドmqttクライアント* /         buildMqtt5Client();


        / **セッションが存在しない場合は、トピックを再度サブスクライブする必要があります* /
        if(!isSessionPresent){             logger.info( "[CLIENT-SUB]サブスクライブトピック:" + MQTT_SUB_TOPIC);             //トピックにサブスクライブ             asyncClient.subscribeWith()。                     topicFilter(MQTT_SUB_TOPIC)                     .qos(MqttQos.EXACTLY_ONCE)                     .send();         }






    }


    パブリック静的Mqtt5BlockingClient buildMqtt5Client(){         / **ブロック客户端* /         クライアント= Mqtt5Client.builder()                 .identifier(MQTT_CLIENT_ID)                 .serverHost(MQTT_SERVER_HOST)                 .serverPort(MQTT_SERVER_PORT)                 .addConnectedListener(新しいMqttClientConnectedListener(){                     @Override                     ます。public void onConnected (MqttClientConnectedContextコンテキスト){                         logger.info( "MQTT onConnected文脈");                     }                 })                 .addDisconnectedListener(新しいMqttClientDisconnectedListener(){                     @Override













                    public void onDisconnected(MqttClientDisconnectedContext context){                         logger.info( "mqtt onDisconnected context");                     }                 })                 //自動再接続(指数関数的に遅延した再接続(遅延1秒、毎回2回後、上限2分)遅延:1秒- >                 2s- > 4s- > ...- > 2min)                 .automaticReconnectWithDefaultConfig()。         buildBlocking (); asyncClient = client.toAsync();







        / ** EmqxJWT认证* /
        String authJwt = JwtUtils.generateJwt(MQTT_CLIENT_ID、MQTT_JWT_SECRET);
        Mqtt5SimpleAuth auth = Mqtt5SimpleAuth.builder()。
                username(MQTT_CLIENT_ID)
                .password(authJwt.getBytes())。
                build();
        Mqtt5ConnAck connAck = null;

 


        / **グローバルメッセージ処理(接続前)* /
        asyncClient.publishes(MqttGlobalPublishFilter.ALL、mqtt5Publish-> {             try {                 byte [] msg = mqtt5Publish.getPayloadAsBytes();                 String msgStr = new String(mqtt5Publish.getPayloadAsBytes()、 " UTF-8 ");                 logger.info(" [CLIENT-RECV] "+ msgStr);             } catch(UnsupportedEncodingException e){                 e.printStackTrace();             }         });








        / **接続ロジック* /
        のtry {             CONNACK = client.connectWith()                     .simpleAuth(AUTH)                     / ** cleanSession =偽* /                     .cleanStart(偽)                     / **セッションが7日に期限切れになる* /                     .sessionExpiryInterval(SESSION_EXPIRATION)                     / **キープアライブ期間* /                     //                     .keepAlive( 60).send();         } catch(Mqtt5ConnAckException e){             e.printStackTrace();             connAck = e.getMqttMessage();         }













        / **接続(パスワードなしの通常の接続)* /
        // Mqtt5ConnAck connAck = client.connect();

        / **セッションがすでに存在するかどうかを確認します* /
        isSessionPresent = connAck.isSessionPresent();
        if(connAck.isSessionPresent()){             logger.info( "session is present:" + connAck.getSessionExpiryInterval()。orElse(-1 ));         }

 

        logger.info(connAck.getReasonCode()+ ":" + connAck.getReasonString()+ ":" + connAck.getResponseInformation());


        if(connAck.getReasonCode()。isError()){             logger.error( "Mqtt5接続に失敗しました!");             System.exit(-1);         }         return client;     } }上記のコア設定:clientId、cleanStart = fasle、sessionExpiry> 0、Qos> = 1、CONNACKセッション現在の処理、必須であり、1つの設定なしでオフラインメッセージを受け入れることはできません。————————————————著作権表示:この記事は、CSDNブロガー「LuoXiaocang EX」のオリジナル記事であり、CC 4.0BY-SA著作権表示に準拠しています。再版のための元のソースリンクそしてこの声明。元のリンク:https://blog.csdn.net/luo15242208310/article/details/103971457
















 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

おすすめ

転載: blog.csdn.net/MYBOYER/article/details/107482127