Как отправить 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();
надеюсь, что это может быть полезно для вас.