2010-07-27 144 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; 
     } 
    }