2015-11-13 12 views
7

Ho un problema con lo sviluppo di un server/client tcp nell'obiettivo c con Bonjour.Il client del server TCP/IP iOS NSStream non è in grado di comunicare

Sul lato server apro correttamente gli stream e utilizzo la funzione handleEvent per inviare e ricevere dati. Ma non so quale sia il modo corretto di inviare e ricevere dati. Ho letto questo ottimo post: Correct way to send data through a socket with NSOutputStream Quindi io uso un sistema di pacchetti in coda per inviare i dati:

switch(eventCode) { 

    case NSStreamEventOpenCompleted: { 
     NSLog(@"Complete"); 

    } break; 

    case NSStreamEventHasSpaceAvailable: { 
     if (stream == _outputStream) 
      [self _sendData]; 
    } break; 

...

- (void)_sendData { 
flag_canSendDirectly = NO; 
NSData *data = [_dataWriteQueue lastObject]; 
if (data == nil) { 
    flag_canSendDirectly = YES; 
    return; 
} 
uint8_t *readBytes = (uint8_t *)[data bytes]; 
readBytes += currentDataOffset; 
NSUInteger dataLength = [data length]; 
NSUInteger lengthOfDataToWrite = (dataLength - currentDataOffset >= 1024) ? 1024 : (dataLength - currentDataOffset); 
NSInteger bytesWritten = [_outputStream write:readBytes maxLength:lengthOfDataToWrite]; 
currentDataOffset += bytesWritten; 
if (bytesWritten > 0) { 
    self.currentDataOffset += bytesWritten; 
    if (self.currentDataOffset == dataLength) { 
     [self.dataWriteQueue removeLastObject]; 
     self.currentDataOffset = 0; 
    } 
} 

}

. Quindi in pratica mando solo i miei dati separati su molti pacchetti. Ma non vedo come ricostruire i dati sul lato client. E penso di non aver capito correttamente l'evento NSStreamEventHasBytesAvailable. Perché qui invio molti pacchetti ma questo evento sul lato client è chiamato una sola volta. E quando ricostruisco i dati dal buffer, i dati sembrano corrotti. Apprezzerei molto se qualcuno potesse chiarire tutto questo, la documentazione non è chiara su questo punto (o forse mi manca un punto ..).

 case NSStreamEventHasBytesAvailable: { 
     if (stream == _inputStream) 
     { 
      //read data 
      uint8_t buffer[1024]; 
      int len; 
      while ([_inputStream hasBytesAvailable]) 
      { 
       len = [_inputStream read:buffer maxLength:sizeof(buffer)]; 
       if (len > 0) 
       { 
        NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding]; 
        //NSData *theData = [[NSData alloc] initWithBytes:buffer length:len]; 
        UnitySendMessage("AppleBonjour_UnityNetworkManager(Clone)", "OnLocalClientReceiveMessageFromServer", [output cStringUsingEncoding:NSUTF8StringEncoding]); 
       } 
      } 
     } 
+0

Hai provato un test semplice? Invia una singola stringa breve. Cosa ottieni nella variabile "output" quando lo fai? FWIW; non ci deve essere una singola chiamata di byte disponibile per ogni invio, saranno combinati se arriveranno in tempo e una lettura li otterrà tutti. Per favore prova questo test e dicci cosa ottieni. –

+0

Oh, ho dimenticato un'altra cosa; puoi testare il ricevitore con un semplice programma tcp come telnet. Collegati alla tua porta e digita del testo. Se il codice del ricevitore funziona, dovresti ottenere direttamente il tuo testo. –

+0

Ok, una semplice stringa ha funzionato. Quindi se invio una stringa più grande del buffer, devo solo ricostruirlo ogni volta che viene chiamato NSStreamEventHasBytesAvailable. Ma come posso avere una notifica quando la stringa è stata inviata completamente? – thegrandwaazoo

risposta

3

Sembra, di utilizzare due variabili currentDataOffset - una variabile di istanza e una proprietà - per lo stesso scopo. Se hai effettivamente bisogno di entrambi, devi impostare 0 su currentDataOffset. Ma penso che il frammento dovrebbe essere:

readBytes += currentDataOffset; 
NSUInteger dataLength = [data length]; 
NSUInteger lengthOfDataToWrite = MIN(dataLength - currentDataOffset, 1024); 
NSInteger bytesWritten = [_outputStream write:readBytes maxLength:lengthOfDataToWrite]; 
if (bytesWritten > 0) { 
    currentDataOffset += bytesWritten; 
    if (currentDataOffset == dataLength) { 
     [self.dataWriteQueue removeLastObject]; 
     currentDataOffset = 0; 
    } 
}