Как отправить ping с помощью клиента Eclipse Paho MQTT?

Мы только начали создавать свою собственную систему уведомлений (из-за требований клиента) для Android и нашли Eclipse Paho (http://www.eclipse.org/paho/), Излишне говорить, что этот проект действительно захватывающий.

Проблема с Android заключается в том, что если процессор находится в состоянии ожидания, клиент MQTT может не получить возможность отправить ping с заданным интервалом. Обходной путь использует AlarmManager, чтобы разбудить его и выполнить задание. В документации на Android говорится:

Диспетчер аварийных сигналов удерживает блокировку слежения за процессором, пока сигнал тревоги приемник onReceive(). Это гарантирует, что телефон не будет спать, пока вы не закончите работу с трансляцией. Когда функция onReceive() возвращается, диспетчер аварийных сигналов отпускает эту блокировку. Это означает, что в некоторых случаях телефон будет спать, как только ваш onReceive() завершает.

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

Мне нужно быть уверенным, что я могу отправить команду ping внутри этого метода onReceive(), в то время как у CPU есть PARTIAL_WAKE_LOCK, поэтому я искал способ отправки по электронной почте ping на сервер, но, похоже, клиент не обнаруживает таких метод. Я что-то упускаю? Или, каков обходной путь здесь, кроме публикации моего собственного "пингового сообщения"? Я хочу избежать этого из-за:

  • Большие накладные расходы
  • Мы гарантируем, что клиенты Android будут только подписчиками, может быть с ACK Mosquitto. Им не разрешат публиковать сообщения.

Ответ 1

Я работаю с MQTT на Android, и я испытал точно такую ​​же проблему.

Как говорит Дейл, в старой версии клиента MQTT использовался явный метод ping(), но, к сожалению, это теперь скрыто.

Самый простой подход и тот, который я использую, - это явно публиковать однобайтовое сообщение для определенной темы, чтобы служить в качестве keepalive. Я не думаю, что это должно многое добавить к накладным расходам вашего приложения, и, хотя я не знаком с Mosquitto ACL, я предполагаю, что каждый клиент может использовать одну и ту же тему "keepalive" и просто предоставлять доступ для записи всем. Это не должно влиять на безопасность, если никто не может читать эту тему.

Альтернативный подход заключался бы в том, чтобы сервер отправил клиенту (-ам) сообщение "keepalive" в QoS 1 или 2 (pub/sub через одну тему для всех для повышения эффективности), поскольку из-за потоков QoS это будет включать клиент, отправляющий сообщение на сервер под обложками; который будет служить в качестве keepalive. Это имеет преимущество, заключающееся в том, что ваши клиенты только подписчики; однако он несовместим с "clean session = false" (поскольку у вас было бы большое количество сообщений, помещенных в очередь для доставки клиентам, которые в автономном режиме ненадолго, что не влияет на производительность при повторном подключении).

К сожалению, это только два обходных решения, о которых я могу сейчас думать.


Кроме того, вкратце, я столкнулся с несколькими проблемами, использующими MqttDefaultFilePersistence на Android, поэтому вы можете быть в курсе этого. В частности, для блокировки файлов и проблем при повторной инстанцировании клиента. Чтобы обойти это, я создал реализацию MqttClientPersistence, построенную поверх базы данных SQLite, и это намного более надежное; вы можете сделать то же самое.

Ответ 2

Я столкнулся с этой проблемой при написании приложений MQTT для Android год назад. Я писал об этом примерно на http://dalelane.co.uk/blog/?p=1599, но, короче говоря, да, я видел ту же проблему, что и вы описываете, где, если центральный процессор спит, когда MQTT клиент должен отправить его ping, тогда пинг никогда не будет отправлен.

Разница в том, что я использовал для вас другую клиентскую библиотеку MQTT (это было до дней Paho), а у клиентской библиотеки, которую я использовал, был метод ping(), который я мог бы назвать. (Полный источник для моей реализации находится по этой ссылке, и он решает эту проблему).

Не можете ли вы расширить реализацию клиентской библиотеки Paho, чтобы включить команду PING? Я предполагаю, что это должна быть небольшая модификация.

Ответ 3

Существует способ изменить код paho и выполнить ping в любое время. Если мы используем тему публикации для поддержания работоспособности, мы должны отправить по меньшей мере 7 или 8 байтов на сервер. Да, 8 байтов все еще не большие данные. Но сердцебиение MQTT составляет всего 2 байта. Мы потеряли лучшее преимущество MQTT.

Посмотрите глубоко в код paho, я изменяю его и пишу публичный метод с именем nnnn() в MQTTClient. Этот метод может отправить MqttPingReq на сервер. преемственность может быть найдена здесь... https://github.com/chinesejie/paho-for-android

Ответ 4

мое решение:

(1) изменить: ClientComms comms; от protected до public (в пакете 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();

надеюсь, что это может быть полезно для вас.