2011-07-13 39 views
5

全部,流來獲取數據 - NSInputStream

我有一個服務器有一個tcp套接字流進行通信。我需要訪問該流並閱讀它需要發送給我的初始數據。

我現在的代碼如下。說實話,我完全失明。我不確定這是否正確,更不用說這項工作是正確的。

-(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]; 

} 

因此,從我看到它的方式,此代碼初始化流,但我如何從流中讀取?

感謝

+1

的代碼塊似乎不正確地分配了'NSInputStream'對象(即有一個'init'但沒有'alloc')。 – newenglander

回答

18

有兩種方式來獲得從流數據:輪詢和使用流事件。

輪詢更簡單,但會阻塞其運行的線程。如果使用此方法,則不需要執行setDelegate:scheduleInRunLoop:forMode:調用。輪詢通過反覆調用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 

使用流事件需要設置委託並將流添加到運行循環。當發生某些事件時(包括接收數據時),流將不會阻塞線程,而會向其代理髮送stream:handleEvent:消息。代表可以從流中檢索數據。下面是一個例子stream:handleEvent:方法:

- (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

對於初學者來說,這是一個有價值的總結性答案,值得進行編輯:現在,通過調用NSInputStream的'read:maxLength:'* inside * if-stmt,如果成功,將不會讀取任何東西獲取流的內部緩衝區。但是我對這個話題沒有足夠的實力來編輯它 - 請問你能解決它嗎? – Wienke

+0

P.S.我想知道爲什麼NSOutputStream沒有一個等效的'getBuffer'方法? – Wienke

+1

@Wienke在本例中,對'read:maxLength:'的調用只是將數據複製到if語句內創建的臨時緩衝區中。如果您尚未擁有包含其中數據的緩衝區,則只需執行此操作。在if語句之後,您應該添加代碼來對緩衝區中的數據執行某些操作,因爲緩衝區只是臨時的。 NSOutputStream可能不提供對內部緩衝區的訪問,因爲它不允許訪問已寫入的數據,並且如果直接寫入緩衝區,則無法知道應該發送該數據。 – ughoavgfhw