12

Android 用の独自のプッシュ通知システム (クライアントの要件により) の構築を開始したところ、Eclipse Paho ( http://www.eclipse.org/paho/ ) を見つけました。言うまでもなく、このプロジェクトは本当にエキサイティングです。

Android の問題は、CPU がスリープ状態にある場合、MQTT クライアントが設定された間隔で ping を送信する機会を得られない可能性があることです。回避策は、AlarmManager を使用して起動し、ジョブを完了させることです。Androidのドキュメントには次のように書かれています:

アラーム マネージャは、アラーム レシーバの onReceive() メソッドが実行されている限り、CPU ウェイク ロックを保持します。これにより、ブロードキャストの処理が完了するまで電話がスリープ状態にならないことが保証されます。onReceive() が戻ると、Alarm Manager はこの wake lock を解放します。これは、onReceive() メソッドが完了するとすぐに電話がスリープする場合があることを意味します。

http://developer.android.com/reference/android/app/AlarmManager.html

CPU に PARTIAL_WAKE_LOCK がある間にその onReceive() メソッド内で ping コマンドを送信できることを確認する必要があるため、サーバーに手動で ping を送信する方法を探していましたが、クライアントはそのようなメソッドを公開していないようです。何か不足していますか?または、自分の「ping メッセージ」を公開する以外に、ここでの回避策は何ですか? 私はそれを避けたい:

  1. より大きなオーバーヘッド
  2. Android クライアントがサブスクライバーのみであることを確認します。Mosquitto の ACL を使用する場合があります。メッセージの公開は許可されません。
4

4 に答える 4

15

私はAndroidでMQTTを使っていくつかの作業を行ってきましたが、まったく同じ問題が発生しました。

Daleが言うように、古いバージョンのMQTTクライアントには明示的なping()メソッドがありましたが、残念ながら、これは現在は隠されています。

最も単純なアプローチ、および私が使用するアプローチは、キープアライブとして機能するように、特定のトピックに1バイトのメッセージを明示的に公開することです。これによってアプリケーションのオーバーヘッドが大幅に増えることはないと思います。MosquittoのACLに精通していませんが、すべてのクライアントに同じ「キープアライブ」トピックを使用させ、すべてに書き込みアクセスを提供できると思います。誰もトピックから読むことができない限り、これはセキュリティに影響を与えるべきではありません。

別のアプローチは、サーバーにQoS 1または2でクライアントに「キープアライブ」メッセージを送信させることです(効率を上げるために、単一のトピックを介してpub / subをすべてに送信します)。これには、QoSフローが含まれるためです。クライアントが内部でサーバーにメッセージを送り返します。キープアライブとして機能します。これには、クライアントをサブスクライバーとしてのみ保持できるという利点があります。ただし、「clean session = false」とは互換性がありません(しばらくオフラインになっているクライアントに配信するために大量のメッセージがキューに入れられるため、再接続時のパフォーマンスに不必要に影響します)。

残念ながら、これらは私が現在考えることができる唯一の2つの回避策です。


また、簡単に言うと、AndroidでMqttDefaultFilePersistenceを使用すると多くの問題が発生したため、これに注意する必要があります。特に、クライアントを再インスタンス化するときのファイルロックと問題に関係します。これを回避するために、SQLiteデータベース上に構築されたMqttClientPersistenceの実装を作成しました。これは、はるかに堅牢です。あなたは同じことをしたいかもしれません。

于 2012-04-09T12:43:26.333 に答える
10

1 年ほど前に Android 用の MQTT アプリを作成しているときに、この問題に遭遇しました。私はそれについてhttp://dalelane.co.uk/blog/?p=1599である程度書いたことがありますが、要するに、はい - MQTT クライアントがping を送信する必要がありますが、ping は送信されません。

違いは、私があなたとは別の MQTT クライアント ライブラリを使用していたこと (これは Paho の時代より前でした) であり、私が使用したクライアント ライブラリには呼び出し可能な ping() メソッドがありました。(私の実装の完全なソースはそのリンクにあり、この問題を解決します)。

Paho クライアント ライブラリの実装を拡張して、PING コマンドを含めることはできませんか? 私はそれがかなり小さな修正であるべきだと思います。

于 2012-04-08T22:59:07.687 に答える
2

paho コードを変更して、いつでも ping を実行する方法があります。パブリッシング トピックを使用してキープ アライブする場合、少なくとも 7 ~ 8 バイトをサーバーに送信する必要があります。はい、8バイトはまだビッグデータではありません。しかし、MQTT のハートビートはわずか 2 バイトです。MQTT の最大の利点を失いました。

paho コードを詳しく調べて、修正し、MQTTClient に nnnn() という名前のパブリック メソッドを記述します。このメソッドは、MqttPingReq をサーバーに送信できます。実装はここにあります... https://github.com/chinesejie/paho-for-android

于 2013-07-20T08:50:43.960 に答える
2

私の解決策:

(1) 変更:ClientComms comms;からprotectedpublic(パッケージ内org.eclipse.paho.client.mqttv3)

public class MqttAsyncClient implements IMqttAsyncClient { // DestinationProvider {
    //...
    public ClientComms comms;  // Add by Ben for pingreq*
    //...
}

(2) 新しいクラスを定義します: (から派生MqttClient)

public class MqttClient2 extends MqttClient {

    public MqttClient2(String serverURI, String clientId,   MqttClientPersistence persistence) throws MqttException {
        super(serverURI, clientId, persistence);
    }

    public void pingreq()  throws MqttException {

        MqttDeliveryToken token = new MqttDeliveryToken(getClientId());
        MqttPingReq pingMsg = new MqttPingReq();
        aClient.comms.sendNoWait(pingMsg, token);

    }
}

(3) どこでも、次のことができます。

MqttClient2 mClient = new MqttClient2(url, mDeviceId, mDataStore);
mClient.pingreq();

これがお役に立てば幸いです。

于 2013-11-16T10:22:58.733 に答える