How to send ping using Eclipse Paho MQTT client?

2020-02-26 07:57发布

We've just started building our own push notification system (due to client's requirement) for Android and found Eclipse Paho (http://www.eclipse.org/paho/). Needless to say, this project is really exciting.

The problem with Android is, if the CPU is in sleep state, the MQTT client may not get the chance to send ping at its set interval. The workaround is using AlarmManager to wake it up and get the job done. The Android documentation says:

The Alarm Manager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the Alarm Manager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes.

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

I need to be sure that I could send the ping command within that onReceive() method while the CPU has PARTIAL_WAKE_LOCK, so I was searching a way to manually sending ping to server but it seems the client doesn't expose any such method. Am I missing something? Or, what is the workaround here except publishing my own "ping message"? I want to avoid that because of:

  1. Larger overhead
  2. We'll ensure that Android clients are subscriber only, may be with Mosquitto's ACL. They will not be allowed to publish messages.

标签: android mqtt
4条回答
Explosion°爆炸
2楼-- · 2020-02-26 08:06

I came across this issue when writing MQTT apps for Android a year or so ago. I've written about it at some length at http://dalelane.co.uk/blog/?p=1599 but in short, yes - I saw the same problem that you describe where if the CPU is asleep when the MQTT client should send it's ping, then the ping never gets sent.

The difference is that I was using a different MQTT client library to you (this was before the days of Paho), and the client library that I used did have a ping() method that I could call. (The full source for my implementation is at that link, and it does solve this problem).

Can you not extend the implementation of the Paho client library to include the PING command? I assume it should be a reasonably small modification.

查看更多
倾城 Initia
3楼-- · 2020-02-26 08:09

I've been doing some work with MQTT on Android and I've experienced exactly the same issue.

As Dale says, the old version of the MQTT client used to have an explicit ping() method, but unfortunately this is now hidden away.

The simplest approach, and the one I use, is to explicitly publish a 1 byte message to a particular topic, to serve as the keepalive. I don't think this should add much to the overhead of your application and, while I'm not familiar with Mosquitto's ACL, I assume you could have every client use the same 'keepalive' topic and just provide write access to all. This shouldn't affect security as long as no-one can read from the topic.

An alternative approach would be to have the server send the client(s) a 'keepalive' message at QoS 1 or 2 (pub/sub through a single topic to all for efficiency) as, due to the QoS flows, this will involve the client sending a message back to the server under the covers; which will serve as the keepalive. This has the advantage of keeping your clients as subscriber only; however it's incompatible with 'clean session = false' (as you would have large amounts of messages queued up for delivery to clients who are offline for a while - needlessly affecting performance on reconnect).

Unfortunately these are the only two workarounds that I can currently think of.


Also, as a brief aside, I've experienced a number of issues using the MqttDefaultFilePersistence on Android, so you might want to be aware of this. In particular to do with file locking and problems when re-instantiating the client. To get around this I've created an implementation of MqttClientPersistence built on top of an SQLite database and this is much more robust; you might want to do the same.

查看更多
疯言疯语
4楼-- · 2020-02-26 08:16

my solution:

(1) modify: ClientComms comms; from protected to public (in package org.eclipse.paho.client.mqttv3)

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

(2) define new class: (derived from 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) anywhere, you can:

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

hope this can be helpfull for you.

查看更多
\"骚年 ilove
5楼-- · 2020-02-26 08:26

There is a way to modify the paho code and make a ping at any time. If we use publishing topic to keep alive, we have to send at least 7 or 8 bytes to server. Yes, 8 bytes is still not big data. But the heartbeat of MQTT is only 2bytes. We have lost the best advantage of MQTT.

Look deeply into the paho code, I modify it and write a public method named nnnn() in MQTTClient. This method could send MqttPingReq to th server. the implemetation can be found here...https://github.com/chinesejie/paho-for-android

查看更多
登录 后发表回答