5

Sto creando un gioco multiplayer usando MPCF. Controlli una nave spaziale sull'iPad usando l'iPhone.Disabilita l'algoritmo di Nagle per NSOutputStream

Sto sperimentando varie quantità di ritardo e latenza e buffering/pause a intervalli e tempi casuali e ora sono atterrato su Apple Technical Q&A NW26 carta che parla di Algoritmo Nagle disabilitato. Sto provando ma il mio programma continua a bloccarsi e non capisco perché. Sembra che CFWriteStreamCopyProperty restituisca sempre NULL.

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode 
{ 
    switch (eventCode) { 
     case NSStreamEventOpenCompleted: 

      // Trying to get a handle to the native socket 
      CFSocketNativeHandle rawsock; 

      // This always return NULL 
      CFDataRef socketData = CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)(stream), kCFStreamPropertySocketNativeHandle); 

      // And this row always crash (coz of socketData being NULL i guess) 
      CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&rawsock); 
      CFRelease(socketData); 

      // Code example from Apple that need a handle to the native socket, that I am trying to get above 
      int err; 
      static const int kOne = 1; 
      err = setsockopt(rawsock, IPPROTO_TCP, TCP_NODELAY, &kOne, sizeof(kOne)); 
      if (err < 0) {  
       err = errno; 
      } 

      break; 

     default: 
      break; 
    } 
} 

Qualsiasi aiuto è apprezzato.

+0

Hai mai trovato una soluzione per questo? Sto anche cercando di ridurre la latenza e senza usare ' sendData: toPeers: withMode: error:' con 'MCSessionSendDataUnreliable', così posso evitare di affrontare la perdita di pacchetti ... – jou

+0

No, mi dispiace. Passato a Bluetooth LE. – bobmoff

+0

Peccato ... Grazie per la risposta. – jou

risposta

5

Partendo dal presupposto che stream è un NSOutputStream, ma potrebbe anche essere passato NSInputStream. Quindi si blocca su quella linea.

Ecco un esempio di codice in grado di gestire entrambi gli scenari e corregge un incidente:

- (void)disableNaglesAlgorithmForStream:(NSStream *)stream { 

    CFDataRef socketData; 

    // Get socket data 
    if ([stream isKindOfClass:[NSOutputStream class]]) { 
     socketData = CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)((NSOutputStream *)stream), kCFStreamPropertySocketNativeHandle); 
    } else if ([stream isKindOfClass:[NSInputStream class]]) { 
     socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)((NSInputStream *)stream), kCFStreamPropertySocketNativeHandle); 
    } 

    // get a handle to the native socket 
    CFSocketNativeHandle rawsock; 

    CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&rawsock); 
    CFRelease(socketData); 

    // Disable Nagle's algorythm 

    // Debug info 
    BOOL isInput = [stream isKindOfClass:[NSInputStream class]]; 
    NSString * streamType = isInput ? @"INPUT" : @"OUTPUT"; 

    int err; 
    static const int kOne = 1; 
    err = setsockopt(rawsock, IPPROTO_TCP, TCP_NODELAY, &kOne, sizeof(kOne)); 
    if (err < 0) { 
     err = errno; 
     NSLog(@"Could Not Disable Nagle for %@ stream", streamType); 
    } else { 
     NSLog(@"Nagle Is Disabled for %@ stream", streamType); 
    } 
} 

Questo dovrebbe essere chiamato proprio nel case NSStreamEventOpenCompleted:

Per chiunque chiedendo il motivo per cui non viene compilato quando viene incollato copia- :

#import <arpa/inet.h>  // for IPPROTO_TCP 
#include <netinet/tcp.h> // for TCP_NODELAY 

Tuttavia, non aiuta con problemi di latenza periodiche. Sto ancora cercando un modo per impedirlo.

ho registrato un semplice video che dimostra il problema e credo che si sta verificando lo stesso: https://www.dropbox.com/s/omdqkbckph4b1y2/Multipeer%20Connectivity.mov?dl=0

EDIT: sono stato in grado di trovare un modo per risolvere un periodico problemi di latenza. È un MCNearbyServiceAdvertiser che causa i problemi. È necessario interrompere la pubblicità di un peer per eliminare i ritardi: chiama un metodo stopAdvertisingPeer sull'istanza MCNearbyServiceAdvertiser subito dopo la connessione riuscita.

MCNearbyServiceAdvertiser *nearbyServiceAdvertiser; 

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state { 

    switch (state) { 

     case MCSessionStateConnected: { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       [self.nearbyServiceAdvertiser stopAdvertisingPeer]; 
      }); 
     ... 
    } 
    ... 
} 

MA i ritardi si spegne solo dopo 30 secondi . Non so come farlo scomparire subito.

+0

Ottima risposta, stavo riscontrando un problema simile nella mia app con cui inviavo molti piccoli pacchetti ogni secondo. Inciampato su questa risposta e sembra aver risolto il mio problema. – mhorgan