2011-07-13 9 views
5

Wszystko,Strumień do uzyskania danych - NSInputStream

Mam serwer, który ma strumień gniazda TCP do komunikacji. Muszę dostać się do tego strumienia i odczytać początkowe dane, które musi mi wysłać.

Mój obecny kod jest następujący. Szczerze mówiąc, idę na to zupełnie ślepo. Nie jestem pewien, czy to jest poprawne, nie mówiąc już o właściwej rzeczy do wykonania.

-(void) initNetworkCommunication 
{ 
    //input stream 
    NSInputStream *iStream; 
    NSURL *url = [url initWithString:@"192.168.17.1:2004"]; 

    [iStream initWithURL:url]; 
    [iStream setDelegate:self]; 
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [iStream open]; 

} 

Tak, jak widzę, ten kod inicjuje strumień, ale jak odczytać ze strumienia?

Dzięki

+1

blok kodu nie wydają się prawidłowo przydzielić obiekt 'NSInputStream' (to jest obiekt' init' ale nie 'alloc'). – newenglander

Odpowiedz

18

Istnieją dwa sposoby, aby uzyskać dane ze strumienia: ankietowanie i używając zdarzenia strumienia.

Polling jest prostszy, ale blokuje wątek, w którym działa. Jeśli używasz tej metody, nie musisz wykonywać połączeń setDelegate: ani scheduleInRunLoop:forMode:. Odpytywanie jest wykonywane przez wielokrotne wywoływanie read:maxLength:.

NSInteger result; 
uint8_t buffer[BUFFER_LEN]; // BUFFER_LEN can be any positive integer 
while((result = [iStream read:buffer maxLength:BUFFER_LEN]) != 0) { 
    if(result > 0) { 
     // buffer contains result bytes of data to be handled 
    } else { 
     // The stream had an error. You can get an NSError object using [iStream streamError] 
    } 
} 
// Either the stream ran out of data or there was an error 

Korzystanie ze zdarzeń strumieniowych wymaga ustawienia delegata i dodania strumienia do pętli uruchamiania. Zamiast blokować wątek, strumień wyśle ​​do jego delegata komunikat o błędzie stream:handleEvent:, gdy wystąpią określone zdarzenia, w tym gdy odbiera dane. Delegat może następnie pobrać dane ze strumienia. Oto przykład stream:handleEvent: metoda:

- (void)stream:(NSInputStream *)iStream handleEvent:(NSStreamEvent)event { 
    BOOL shouldClose = NO; 
    switch(event) { 
     case NSStreamEventEndEncountered: 
      shouldClose = YES; 
      // If all data hasn't been read, fall through to the "has bytes" event 
      if(![iStream hasBytesAvailable]) break; 
     case NSStreamEventHasBytesAvailable: ; // We need a semicolon here before we can declare local variables 
      uint8_t *buffer; 
      NSUInteger length; 
      BOOL freeBuffer = NO; 
      // The stream has data. Try to get its internal buffer instead of creating one 
      if(![iStream getBuffer:&buffer length:&length]) { 
       // The stream couldn't provide its internal buffer. We have to make one ourselves 
       buffer = malloc(BUFFER_LEN * sizeof(uint8_t)); 
       freeBuffer = YES; 
       NSInteger result = [iStream read:buffer maxLength:BUFFER_LEN]; 
       if(result < 0) { 
        // error copying to buffer 
        break; 
       } 
       length = result; 
      } 
      // length bytes of data in buffer 
      if(freeBuffer) free(buffer); 
      break; 
     case NSStreamEventErrorOccurred: 
      // some other error 
      shouldClose = YES; 
      break; 
    } 
    if(shouldClose) [iStream close]; 
} 
+0

Jest to cenna odpowiedź dla nas, początkujących, i warto ją edytować: W obecnej formie, z wezwaniem do NSInputStream 'read: maxLength:' * inside * if-stmt, nic nie przeczytasz, jeśli odniesiesz sukces w uzyskaniu wewnętrznego bufora strumienia. Ale nie jestem wystarczająco solidny w temacie, aby samemu go edytować - czy mógłbyś to naprawić? – Wienke

+0

P.S. Zastanawiam się, dlaczego NSOutputStream nie ma równoważnej metody getBuffer? – Wienke

+1

@Wienke W tym przykładzie wywołanie funkcji 'read: maxLength:' po prostu kopiuje dane do bufora tymczasowego utworzonego w instrukcji if. Trzeba to zrobić tylko, jeśli nie masz jeszcze bufora z danymi w nim zawartymi. Natychmiast po instrukcji if powinieneś dodać kod, aby zrobić coś z danymi w buforze, ponieważ bufor jest tylko tymczasowy. NSOutputStream prawdopodobnie nie zapewnia dostępu do wewnętrznego bufora, ponieważ nie pozwala na dostęp do danych, które już napisałeś, i gdybyś napisał bezpośrednio do bufora, nie wiedziałby, że powinien wysłać te dane. – ughoavgfhw

Powiązane problemy