2012-04-08 7 views
11

Abbiamo appena iniziato a creare il nostro sistema di notifica push (per esigenze del cliente) per Android e trovato Eclipse Paho (http://www.eclipse.org/paho/). Inutile dire che questo progetto è davvero eccitante.Come inviare il ping utilizzando il client Eclipse Paho MQTT?

Il problema con Android è, se la CPU è in stato di sospensione, il client MQTT potrebbe non avere la possibilità di inviare ping al suo intervallo impostato. La soluzione alternativa è usare AlarmManager per riattivarlo e portare a termine il lavoro. La documentazione Android dice:

Il Gestore allarme contiene un blocco scia CPU finché il metodo OnReceive() del destinatario dell'allarme è in esecuzione. Ciò garantisce che il telefono non si addormenta fino al termine della gestione della trasmissione. Una volta che onReceive() ritorna, Alarm Manager rilascia questo wake lock. Ciò significa che il telefono in alcuni casi verrà interrotto non appena viene completato il metodo onReceive().

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

ho bisogno di essere sicuro che ho potuto inviare il comando ping all'interno di tale metodo OnReceive() mentre la CPU ha PARTIAL_WAKE_LOCK, quindi stavo cercando un modo per inviare manualmente ping al server, ma sembra il client non espone alcun metodo di questo tipo. Mi sto perdendo qualcosa? Oppure, qual è la soluzione qui tranne la pubblicazione del mio "messaggio ping"? Voglio evitare che a causa di:

  1. ingrandita della testa
  2. Ci assicuriamo che i client Android sono abbonati solo, può essere con ACL mosquitto. Non saranno autorizzati a pubblicare messaggi.
+0

Durante questa operazione, hai notato che il servizio MqttService si interrompe se si allontana l'app dalle app recenti? Dopodiché, non vengono ricevuti messaggi e si è disconnessi dal broker. Come (se lo hai) hai risolto questo problema? –

risposta

14

Ho lavorato con MQTT su Android e ho riscontrato esattamente lo stesso problema.

Come dice Dale, la vecchia versione del client MQTT utilizzava un metodo ping() esplicito, ma sfortunatamente questo è ora nascosto.

L'approccio più semplice, e quello che uso, è pubblicare esplicitamente un messaggio da 1 byte su un argomento particolare, da utilizzare come keepalive. Non penso che questo dovrebbe aggiungere molto al sovraccarico della vostra applicazione e, anche se non ho familiarità con l'ACL di Mosquitto, presumo che potreste avere ogni cliente che usa lo stesso argomento 'keepalive' e solo fornire accesso in scrittura a tutti. Questo non dovrebbe influire sulla sicurezza finché nessuno può leggere dall'argomento.

Un approccio alternativo sarebbe quello di far inviare al client (s) un messaggio "keepalive" a QoS 1 o 2 (pub/sub attraverso un singolo argomento a tutti per efficienza) poiché, a causa dei flussi QoS, ciò comporterà che il client invii un messaggio al server sotto le copertine; che servirà da keepalive. Questo ha il vantaggio di mantenere i tuoi clienti solo come abbonati; tuttavia è incompatibile con 'clean session = false' (come avresti grandi quantità di messaggi in coda per il recapito ai client che sono offline per un po '- influendo inutilmente sul rendimento della riconnessione).

Sfortunatamente queste sono le uniche due soluzioni alternative che posso attualmente pensare.


Inoltre, come una breve parte, ho sperimentato una serie di questioni che utilizzano il MqttDefaultFilePersistence su Android, così si potrebbe desiderare di essere consapevoli di questo. In particolare a che fare con il blocco dei file e problemi durante la nuova istanziazione del client. Per aggirare questo ho creato un'implementazione di MqttClientPersistence costruita su un database SQLite e questo è molto più robusto; potresti voler fare lo stesso.

+0

Grazie! Il motivo di non permettere ai client di pubblicare è che ho visto la [lunghezza massima] (https://answers.launchpad.net/ mosquitto/+ question/188424) dei messaggi supportati da MQTT/Mosquitto è troppo alto, in base al link ~ 260 MB. Pensi che questo metta una minaccia sul server? Come i broker gratuiti (Mosquitto/RSMB) non supportano SSL la semplice autenticazione basata su nome utente/password non mi sembrava abbastanza sicura, quindi volevo vietare l'accesso a chiunque tranne il server stesso, dove non è possibile l'attacco Man-in-the-middle. questa è solo una supposizione. – MHK

+0

Un'altra cosa sulla nota a margine: Eclipse Paho ha una classe di persistenza della memoria interna 'org.eclipse.paho.client.mqttv3.internal.MemoryPersistence', la sto usando per evitare i fastidi che hai menzionato. – MHK

+0

Hmm, difficile. Immagino che dipenda quanto sia robusto il broker e se possa gestire qualcuno che lo bombarda con messaggi di ~ 260 MB nel tentativo di inondarlo; in quanto questo è l'unico attacco che penso ti lascerebbe aperto. Come dici tu, username/password non forniranno alcuna protezione in quanto potrebbero essere annusati sul filo. – stephendnicholas

10

Mi sono imbattuto in questo problema durante la scrittura di app MQTT per Android un anno fa circa. Ne ho già parlato a lungo a http://dalelane.co.uk/blog/?p=1599 ma in breve, sì, ho visto lo stesso problema in cui descrivi dove se la CPU è addormentata quando il client MQTT deve inviare il suo ping, quindi il ping non viene mai inviato.

La differenza è che stavo usando una libreria client MQTT diversa (questo era prima dei giorni di Paho), e la libreria client che ho usato aveva un metodo ping() che potevo chiamare. (La fonte completa per la mia implementazione è a quel link e risolve questo problema).

Non è possibile estendere l'implementazione della libreria client Paho per includere il comando PING? Presumo che dovrebbe essere una modifica ragionevolmente piccola.

+0

Grazie per la risposta. Ho visto il tuo post prima di iniziare a lavorarci, è una grande risorsa sull'argomento, devo ammettere. Ho pensato di "estendere" la libreria client Paho, ma sembra che non sia possibile (in senso positivo). Memorizza l'istanza della classe ClientComms all'interno di un campo privato e quell'oggetto ClientComms memorizza l'oggetto ClientState al suo interno, anche in un campo privato. ClientState è responsabile della gestione dei ping (richiesta, risposta e ora). Dovrò modificare il core in questo caso, rendendolo un casino :( – MHK

2

C'è un modo per modificare il codice paho e fare un ping in qualsiasi momento. Se usiamo l'argomento di pubblicazione per restare in vita, dobbiamo inviare almeno 7 o 8 byte al server. Sì, 8 byte non sono ancora grandi dati. Ma il battito cardiaco di MQTT è solo di 2 byte. Abbiamo perso il miglior vantaggio di MQTT.

Guardare a fondo il codice paho, lo modifico e scrivo un metodo pubblico chiamato nnnn() in MQTTClient. Questo metodo potrebbe inviare MqttPingReq al server. l'Implementazione può essere trovato qui ... https://github.com/chinesejie/paho-for-android

2

la mia soluzione:

(1) modificare: ClientComms comms;protected-public (nella confezione org.eclipse.paho.client.mqttv3)

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

(2) definire nuova classe: (derivato da 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) da nessuna parte, yo Potete:

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

spero che questo possa essere utile per voi.

+0

per evitare di modificare la classe 'org.eclipse.paho.client.mqttv3.MqttAsyncClient' (passaggio 1) è possibile creare la classe MqttClient2 in un pacchetto denominato' org.eclipse.paho.client.mqttv3' (avviato al passaggio 2 immediatamente) – madlymad

+0

Buona idea. Grazie! –

+0

Funziona solo fino a mqtt-client-0.4.0. Nel campo mqtt-client-0.4.1-SNAPSHOT un client della classe MqttClient è stato modificato in privato da protetto quindi non accessibile nella classe figlio. C'è qualche altra soluzione per farlo funzionare per o.4.1-SNAPSHOT e successivi? – Pawan

Problemi correlati