如何使用Eclipse Paho MQTT客户端发送ping?

时间:2012-04-08 19:13:09

标签: android mqtt

我们刚刚开始为Android构建我们自己的推送通知系统(由于客户的要求),并找到了Eclipse Paho(http://www.eclipse.org/paho/)。不用说,这个项目非常令人兴奋。

Android的问题是,如果CPU处于睡眠状态,MQTT客户端可能无法以设置的间隔发送ping。解决方法是使用AlarmManager将其唤醒并完成工作。 Android文档说:

  

只要报警,报警管理器就会保持CPU唤醒锁定   接收者的onReceive()方法正在执行。这保证了   在完成广播处理后,手机才会睡眠。   一旦onReceive()返回,Alarm Manager就会释放此唤醒锁定。   这意味着手机在某些情况下会尽快睡觉   onReceive()方法完成。

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

我需要确保我可以在该onReceive()方法中发送ping命令,而CPU有PARTIAL_WAKE_LOCK,所以我正在搜索手动发送ping到服务器的方法,但似乎客户端没有暴露任何这样的方法。我错过了什么吗?或者,除了发布我自己的“ping消息”之外,这里的解决方法是什么?我想避免这种情况,因为:

  1. 更大的开销
  2. 我们将确保Android客户端仅为订户,可能是Mosquitto的ACL。他们不会被允许发布消息。

4 个答案:

答案 0 :(得分:15)

我一直在Android上使用MQTT做一些工作,我遇到了完全相同的问题。

正如Dale所说,旧版本的MQTT客户端曾经有一个明确的ping()方法,但不幸的是现在已经隐藏了它。

最简单的方法,也就是我使用的方法,是明确地向特定主题发布1字节消息,以充当keepalive。我认为这不应该增加应用程序的开销,虽然我不熟悉Mosquitto的ACL,但我认为你可以让每个客户端使用相同的“keepalive”主题并只提供对所有人的写访问权限。只要没有人可以从主题中读取,这不应该影响安全性。

另一种方法是让服务器在QoS 1或2发送客户端的“keepalive”消息(通过单个主题发布/发布以提高效率),因为QoS流量,将涉及客户端将消息发送回封底的服务器;这将作为keepalive。这样做的好处是只保留您的客户为订户;但它与'clean session = false'不兼容(因为你会将大量的消息排队等待交付给离线一段时间的客户端 - 不必要地影响重新连接的性能)。

不幸的是,这些是我目前唯一能想到的两种解决方法。


另外,作为一个简短的说法,我在Android上使用MqttDefaultFilePersistence时遇到了很多问题,所以你可能想知道这一点。特别是在重新实例化客户端时与文件锁定和问题有关。为了解决这个问题,我创建了一个构建在SQLite数据库之上的MqttClientPersistence实现,这个实现更加强大;你可能想要这样做。

答案 1 :(得分:10)

我在大约一年前为Android编写MQTT应用程序时遇到过这个问题。我已经在http://dalelane.co.uk/blog/?p=1599处写了一些篇幅但是简而言之,是的 - 我看到了同样的问题,你描述了当MQTT客户端发送它的ping时CPU是否处于睡眠状态时,ping永远不会被发送。

不同之处在于我正在使用不同的MQTT客户端库(这是在Paho时代之前),而我使用的客户端库确实有一个我可以调用的ping()方法。 (我的实现的完整源代码在那个链接上,它确实解决了这个问题)。

您是否可以扩展Paho客户端库的实现以包含PING命令?我认为它应该是一个相当小的修改。

答案 2 :(得分:2)

有一种方法可以随时修改paho代码并进行ping操作。如果我们使用发布主题来保持活跃,我们必须向服务器发送至少7或8个字节。是的,8个字节仍然不是大数据。但MQTT的心跳只有2字节。我们失去了MQTT的最大优势。

深入研究paho代码,我修改它并在MQTTClient中编写一个名为nnnn()的公共方法。此方法可以将MqttPingReq发送到服务器。实现可以在这里找到...... https://github.com/chinesejie/paho-for-android

答案 3 :(得分: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();
希望这对你有所帮助。