2012-10-28 8 views
6

Ho un dispositivo sulla rete che esegue il multicasting di un file molto piccolo tramite UDP. L'app iOS che sto sviluppando è responsabile della lettura di questi pacchetti e ho scelto di utilizzare GCDAsyncUdpSocket per farlo. Il file viene inviato ogni mezzo secondo, tuttavia non lo ricevo quasi spesso (ricevendo solo circa ogni 3-10 secondi).GCDAsyncUdpSocket su iOS mancanti datagrammi multicast

Pensando che potrebbe essere un problema con il dispositivo, ho iniziato a monitorare il traffico con Wireshark. Questo sembrava riflettere ciò che vedevo nella mia app fino a quando non ho abilitato la "Modalità Monitor" in Wireshark, a quel punto ogni pacchetto UDP veniva catturato. Inoltre, il simulatore iOS ha iniziato a ricevere tutti i pacchetti mancanti poiché condivide la NIC con il Mac su cui sto sviluppando.

C'è un modo per abilitare "Modalità Monitor" su un dispositivo iOS o qualcosa che mi manca che consentirebbe ai pacchetti mancanti di entrare? Vedo anche che esiste un metodo readStream in GCDAsyncUdpSocket. Forse ho bisogno di usare questo invece di beginReceiving? Anche se non so come impostare i flussi in Objective-C, se questo è il caso.

Ecco il mio codice di prova come è ora:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    NSLog(@"View Loaded"); 
    [self setupSocket];    
} 

- (void)setupSocket 
{ 
    udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; 
    NSError *error = nil; 
    if (![udpSocket bindToPort:5555 error:&error]) 
    { 
     NSLog(@"Error binding to port: %@", error); 
     return; 
    } 
    if(![udpSocket joinMulticastGroup:@"226.1.1.1" error:&error]){ 
     NSLog(@"Error connecting to multicast group: %@", error); 
     return; 
    } 
    if (![udpSocket beginReceiving:&error]) 
    { 
     NSLog(@"Error receiving: %@", error); 
     return; 
    } 
    NSLog(@"Socket Ready"); 
} 

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data 
     fromAddress:(NSData *)address 
withFilterContext:(id)filterContext 
{ 
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
    if (msg) 
    { 
     NSLog(@"RCV: %@", msg); 
    } 
    else 
    { 
     NSString *host = nil; 
     uint16_t port = 0; 
     [GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address]; 
     NSLog(@"Unknown message from : %@:%hu", host, port); 
    } 
} 

soluzione per chi arriva in cerca qui in futuro:

Sulla base di risposta di ilmiacs, ero in grado di ridurre in modo significativo il numero di pacchetti mancanti eseguendo il ping del dispositivo iOS di destinazione. Utilizzando un Mac, ho eseguito questo nel terminale -

sudo ping -i 0.2 -s 4 <Target IP> 

Ora che ho in esecuzione con un Mac il ping sul dispositivo iOS, ho intenzione di guardare in esempi ping iOS di Apple e vedere se posso avere il dispositivo ping stesso per stimolare il proprio adattatore wireless (127.0.0.1).

+0

ci si rende conto che i pacchetti UDP sono ** non ** garantiti per la consegna in base alla progettazione? la tua applicazione deve essere in grado di gestire questo caso. –

+0

Sì, so che UDP è inaffidabile, ma potrebbe davvero essere la causa del fatto che molti pacchetti non vengano scoperti? Inoltre, l'app riceve ogni pacchetto senza problemi finché la scheda NIC ha attivato la modalità monitor. – Squatch

+0

@Squatch puoi dire quale dispositivo hai usato? –

risposta

12

Attraverso il mio lavoro sulla messa in rete di applicazioni per dispositivi iOS che ho rivelato che le loro schede di rete hanno due diverse modalità, chiamiamoli attiva e passiva. Non sono riuscito a trovare alcuna documentazione su questo. Qui sono i miei risultati:

  1. Finché in modalità attiva, l'adattatore è abbastanza reattivo. Ho tempi di risposta di 3-5ms.

  2. Dopo un certo periodo di inattività, la scheda di rete di iOS passa dalla modalità attiva a quella passiva. Il tempo necessario a questo, dipende dal modello del dispositivo reale. 3 ° gen iPad è di circa 200ms. Per l'iPhone 4 è più simile a 50ms.

  3. Una richiesta ping o un pacchetto TCP sposterà l'adattatore dalla passivo alla modalità attiva. Questo può richiedere da 50ms a 800ms, con una media di circa 200ms.

Questo comportamento è completamente riproducibile mediante l'emissione di comandi ping. Per esempio.

ping -i 0.2 <ios-device-ip> 

imposta l'intervallo di ping per 200ms e mantiene la mia scheda di rete iPad nello stato attivo.

Questo comportamento è del tutto coerente con le sue osservazioni, se l'adattatore (il più delle volte) ignora i pacchetti UDP in modalità passiva. L'attività wireshark probabilmente la mantiene in modalità attiva, quindi otterrebbe gli UDP.

Verificare se il trucco ping aiuta.

Uno probabilmente potrebbe mantenere la scheda di rete di iDevice nello stato attivo aprendo e connettendo due socket sul dispositivo stesso e inviando regolarmente pacchetti. Ciò introdurrebbe un sovraccarico minimo.

Per quanto riguarda il motivo per cui Apple ha deciso di implementare tale funzione, non posso che speculare. Ma probabilmente mantenere l'adattatore attivo costa una carica sufficiente della batteria per legittimare una tale scelta di design.

Spero che questo aiuti.

+0

Hmmmm molto interessante. Non avrei mai pensato di provarlo. Ci proverò stasera. – Squatch

+0

Sì, siamo rimasti sconcertati sul comportamento di latenza per almeno un mese. ;-) – ilmiacs

+0

Ha funzionato! Mi mancano ancora alcuni dei pacchetti ma è una quantità trascurabile. Grazie mille. – Squatch

1

Ho avuto lo stesso problema.

partire l'indicatore di attività della rete risolto il problema per me:

UIApplication* app = [UIApplication sharedApplication]; 
app.networkActivityIndicatorVisible = YES; 
0

Se si desidera visualizzare il pacchetto sul dispositivo iOS, è possibile legare il dispositivo iOS ad un Mac e montare l'adattatore WiFi utilizzando shell command rvictl . È quindi possibile utilizzare wireshark, Tcpdump e così via per monitorare il traffico sull'interfaccia 802.11 sul dispositivo iOS.

Per quanto riguarda la mancata ricezione dei dati da 3 a 7 secondi - Molto probabilmente il dispositivo sta entrando in modalità di risparmio energetico (IEEE PSM) che è una funzione 802.11 che mette essenzialmente in attesa la NIC wireless.
Modalità PSM can yield poor performance on devices - soprattutto nel tuo caso in cui si verificano scoppi di dati periodici ogni 1/2 secondo. Il tuo ping periodico sta svegliando la NIC.