2015-06-03 12 views
9

Sto usando server ejabberd e ios xmppframework. ci sono due clienti, A e B.I messaggi xmpp sono persi quando la connessione client perse improvvisamente

  1. Quando A e B sono in linea, A può inviare un messaggio a B con successo.
  2. Se B è offline, B può ricevere il messaggio quando B è di nuovo in linea.
  3. Ma quando B viene improvvisamente/inaspettatamente perso la connessione, ad esempio la chiusura manuale wi-fi, il messaggio inviato da A viene perso. B non sarà mai ricevere questo messaggio.

Credo che la ragione è che B ha perso il collegamento improvvisamente e il server ancora che B è online. Pertanto il messaggio offline funziona in questa condizione.

Quindi la mia domanda è come garantire che il messaggio inviato da A venga ricevuto da B? Per garantire che non ci siano messaggi persi.

risposta

8

Ho passato l'ultima settimana a cercare di rintracciare i messaggi mancanti nella mia app di messaggistica XMPPFramework ed eJabberd. Ecco i passaggi completi che ho seguito per garantire la consegna dei messaggi e quali sono gli effetti di ogni passaggio.

Mod_offline

nel file di configurazione ejabberd.yml assicurarsi di avere questo nelle regole di accesso:

max_user_offline_messages: 
    admin: 5000 
    all: 100 

e questo nella sezione moduli:

mod_offline: 
    access_max_user_messages: max_user_offline_messages 

Quando il server sa che il destinatario di un messaggio è offline, lo memorizzerà e lo recapiterà quando si riconnetteranno.

Ping (XEP-199)

xmppPing = XMPPPing() 
xmppPing.respondsToQueries = true 
xmppPing.activate(xmppStream) 

xmppAutoPing = XMPPAutoPing() 
xmppAutoPing.pingInterval = 2 * 60 
xmppAutoPing.pingTimeout = 10.0 
xmppAutoPing.activate(xmppStream) 

Ping si comporta come un battito cardiaco in modo che il server sa quando l'utente non è in linea, ma non scollegare normalmente. È una buona idea non fare affidamento su questo disconnettendo su applicationDidEnterBackground ma quando il client perde connettività o lo streaming si disconnette per ragioni sconosciute c'è una finestra di tempo in cui un client è offline ma il server non lo sa ancora perché il ping wasn si aspetta fino a qualche tempo in futuro. In questo scenario il messaggio non viene consegnato e non viene memorizzato per il recapito offline.

flusso Management (XEP-198)

xmppStreamManagement = XMPPStreamManagement(storage: XMPPStreamManagementMemoryStorage(), dispatchQueue: dispatch_get_main_queue()) 
xmppStreamManagement.autoResume = true 
xmppStreamManagement.addDelegate(self, delegateQueue: dispatch_get_main_queue()) 
xmppStreamManagement.activate(xmppStream) 

e poi in xmppStreamDidAuthenticate

xmppStreamManagement.enableStreamManagementWithResumption(true, maxTimeout: 100) 

Ci siamo quasi.Il passo finale è quello di tornare alla ejabberd.yml e aggiungere questa riga alla sezione porte in ascolto sotto access: c2s:

resend_on_timeout: true 

flusso di gestione aggiunge req/strette di mano AKN dopo ogni consegna dei messaggi. A parte ciò, non avrà alcun effetto sul lato server a meno che non sia impostato resend_on_timeout (che non è predefinito su eJabberd).

C'è un caso limite finale che deve essere considerato quando il riconoscimento di un messaggio ricevuto non arriva al server e decide di tenerlo per la consegna offline. La prossima volta che il client accede, è probabile che riceva un messaggio duplicato. Per gestirlo, impostiamo quel delegato per XMPPStreamManager. Implementare lo xmppStreamManagement getIsHandled: e se il messaggio ha un corpo di chat, impostare isHandledPtr su falso. Quando si costruisce un messaggio in uscita aggiungere un xmppElement con un ID univoco:

let xmppMessage = XMPPMessage(type: "chat", to: partnerJID) 
let xmppElement = DDXMLElement(name: "message") 
xmppElement.addAttributeWithName("id", stringValue: xmppStream.generateUUID()) 
xmppElement.addAttributeWithName("type", stringValue: "chat") 
xmppElement.addAttributeWithName("to", stringValue: partnerJID.bare()) 
xmppMessage.addBody(message) 
xmppMessage.addChild(xmppElement) 
xmppMessage.addReceiptRequest() 
xmppStream.sendElement(xmppMessage) 

Poi, quando si riceve un messaggio, informare il gestore dei flussi che il messaggio è stato gestito con xmppStreamManager.markHandledStanzaId(message.from().resource)

Lo scopo di questa fase finale è quello di stabilire un identificatore univoco che è possibile aggiungere allo XMPPMessageArchivingCoreDataStorage e verificare la presenza di duplicati prima della visualizzazione.

+0

Questo è esattamente ciò che ho fatto. – xhsoldier

+0

Grazie amico !! questo è davvero utile post .. – nikBhosale

3

Se B si disconnette improvvisamente, l'utente A deve verificare se B è online/offline mentre invia un messaggio all'utente B. Se l'utente B non è in linea, l'utente A deve caricare quel messaggio sul server utilizzando il servizio Web. E l'utente B deve chiamare il servizio web sotto la funzione.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

Quindi l'utente B riceverà tutto il messaggio non in linea perso a causa della connessione persa.

+0

questa è una soluzione. Ho anche risolto questo problema con XEP-198 e XEP-199 – xhsoldier

7

Suppongo che B abbia perso improvvisamente la connessione e che il server pensi ancora che B sia online. Quindi il messaggio offline funziona sotto questa condizione

Sì, si è assolutamente corretto, questa è una limitazione ben nota delle connessioni TCP.

Ci sono due approcci al problema

1 Lato server

Come posso vedere che si sta utilizzando ejabbed come server di XMPP è possibile implementare mod_ping, attivazione di questo modulo permette lato server heartbeat [ping], in caso di connessione interrotta al server [ejabbed] sarà provare a inviare heartbeat alla connessione e rileverà la connessione è persa tra server e client. L'utilizzo di questo metodo ha un svantaggio, modulo mod_ping ha proprietà chiamata ping_interval che stati la frequenza di invio battito cardiaco a clienti collegati qui in basso limite è di 32 secondi qualsiasi valore inferiore a 32 viene ignorato dal ejabbed, significa avete 32 secondi finestra nera in cui i messaggi possono essere persi se l'utente sta seminando come linea

2 lato client

Dal lato client è possibile implementare Message Delivery Receipts meccanismo.Con ogni messaggio di chat inviare una ricevuta all'utente del destinatario di non appena l'utente ricevente riceve il messaggio restituire questo ID di ricevuta . In questo modo è possibile rilevare che il tuo messaggio è effettivamente consegnato al ricevitore . Se non si riceve tale conferma tra determinati intervalli di tempo è possibile visualizzare l'utente come non in linea localmente (sul telefono cellulare ), archiviare eventuali ulteriori messaggi a questo utente come messaggio offline localmente [nel database SQLLight] e attendere la presenza offline stanza per quell'utente , non appena si riceve la stanza di presenza offline significa che il server ha finalmente rilevato che la connessione a quell'utente è andata persa e rende lo stato utente non in linea, ora è possibile inviare tutti i messaggi a quell'utente, che sarà nuovamente memorizzato come messaggi offline sul server. Questo è il miglior approccio per evitare black-window.

Conclusione È possibile utilizzare Approccio 2 e la progettazione si cliente tal modo, è possibile utilizzare anche Approccio 1 insieme con l'approccio per ridurre al minimo 2 server di rotta tempo di connessione detrazione.

Problemi correlati