2010-07-27 142 views
1

這是Asynchronous IO with CFWriteStream兄弟的問題。我使用CFReadStreamScheduleWithRunLoop和CFReadSteamRead做異步IO。我們如何安全地檢索阻止的所有日期?我們假設一個消息的實際大小是1200(但我們不知道),而且我的讀取緩衝區的大小是1024.對CFReadStreamRead的調用將檢索多達1024字節的數據,但由於我們不願意不知道消息的大小,我們應該反覆調用CFReadStreamRead。問題是,因爲我們不知道有多少流套接字已接收到數據時,CFReadStreamRead可能從第二個呼叫阻塞。我們如何避免這個問題?異步IO與CFReadStream

謝謝!再次CFReadStreamHasBytesAvailable()

+0

爲了明確這一點:當我得到一個kCFStreamEventHasBytesAvailable通知爲文檔說,第一次調用CFReadStreamRead將是安全的。但是,我們不知道CFReadStreamRead返回的原因是否是因爲緩衝區是不夠大或流套接字沒有更多的數據。如果在第一次通知之前收到所有1200字節的數據,我們可能無法獲得其他數據的額外通知。所以我們應該再次調用CFReadStreamRead,並且不保證第二個調用不會被阻塞。這個假設是否正確? – Kay 2010-07-28 07:42:24

回答

2

請撥打流,看它是否仍然安全從中讀取數據(或者,如果知道的唯一方法是嘗試)。

0

我添加了一個示例代碼,該做的工作對我來說。它使用CFReadStreamHasBytesAvailable()。檢查流的狀態非常重要,否則可能會導致無限循環。我的例子還包括超時處理。

NSMutableData* bodyData = [NSMutableData dataWithCapacity:kHTTPReadStreamBufferSize]; 
    NSDate* startTimeStamp = [NSDate date]; 

    while (TRUE) { 
     if (CFReadStreamHasBytesAvailable(httpReadStream)) { 
      startTimeStamp = [NSDate date]; 
      UInt8* streambuffer = malloc(kHTTPReadStreamBufferSize); 
      int readBytes = CFReadStreamRead (httpReadStream,streambuffer,kHTTPReadStreamBufferSize); 
      NSLog(@"Read: %d",readBytes); 
      [bodyData appendBytes:streambuffer length:readBytes]; 
      free(streambuffer); 
     } 

     if (CFReadStreamGetStatus(httpReadStream) == kCFStreamStatusError) { 
      *error = (NSError*)CFReadStreamCopyError (httpReadStream); 
      if ([*error code] == 61) { 
       NSLog(@"Error occured: %d",[*error code]); 
       // connection refused 
       [PlusError errorForDomainWithCode:kPlusHostUnreachable errorDescription:NSLocalizedString(@"kPlusHostUnreachable",@"") 
            underlyingError:nil url:nil toError:error]; 

      } 
      *responseHeader = nil; 
      *bodyContent = nil; 
      break;   
     } 

     if (CFReadStreamGetStatus(httpReadStream) == kCFStreamStatusAtEnd) { 
      NSLog(@"Stream reached end!"); 
      *responseHeader = (CFHTTPMessageRef)CFReadStreamCopyProperty(httpReadStream, kCFStreamPropertyHTTPResponseHeader);  
      *error = nil; 
      break; 
     } 

     // timeout management 
     NSTimeInterval timeInterval = [startTimeStamp timeIntervalSinceNow]*-1; 
     if (timeInterval >= kHTTPReadTimeOutTimeInSeconds) { 
      [PlusError errorForDomainWithCode:kPlusResourceLoadingError errorDescription:NSLocalizedString(@"kPlusResourceLoadingError",@"") 
           underlyingError:nil url:nil toError:error]; 

      break; 
     } 
    }