0

我有在 iOS 上使用 CFReadStreamRead 的旧代码,但如果没有/丢失连接,CFReadStreamRead 将永远阻塞。如何将 CFReadStreamRead 设置为超时?

提前致谢

4

4 回答 4

3

@Michael Wildermuth 是的,打开流并修复它时出错。遇到同样问题的人,下面的代码会有所帮助。

NSURL *url = [NSURL URLWithString:@"http://www.google.com"];
CFStreamClientContext dataStreamContext = {0, (__bridge void *)(self), NULL, NULL, NULL};

CFHTTPMessageRef message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("GET"), (__bridge CFURLRef)url, kCFHTTPVersion1_1);

NSString *header;
NSDictionary *requestHeaders = [NSDictionary dictionaryWithObject:@"application/html;charset=UTF-8" forKey:@"Content-Type"];
for (header in requestHeaders) {
    CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)header, (__bridge CFStringRef)[requestHeaders objectForKey:header]);
}

CFHTTPMessageSetBody(message, (CFDataRef)(CFSTR("")));

CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, message);
CFOptionFlags events = kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;


if(CFReadStreamSetClient(readStream, events, EvenCallBack, &dataStreamContext)){
    CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
}

CFReadStreamOpen(readStream);

而对于回调函数,

void EvenCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo){


if(CFReadStreamHasBytesAvailable(readStream))
{
    uint8_t buf[1024];
    unsigned int len = 1024;

    CFIndex numBytesRead = CFReadStreamRead(readStream, buf, len);

    NSMutableData* data = [[NSMutableData alloc] init];
    [data appendBytes:&buf length:numBytesRead];

    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    NSLog(@"Network read (%d): %@", len, str);
}else {
    return;
}

CFHTTPMessageRef message = (CFHTTPMessageRef)CFReadStreamCopyProperty((CFReadStreamRef)readStream, kCFStreamPropertyHTTPResponseHeader);
if (!message) {
    NSLog(@"No message");
}

}

谢谢!

于 2012-12-03T18:33:55.593 回答
2

我最终使用了一个自制的超时。代码是这样的:

uint64_t start = get_current_time();

while(TRUE) {
     if(CFReadStreamHasBytesAvailable(stream) == TRUE) {
          while ((bytes_read = CFReadStreamRead(stream, buffer, read_size)) > 0) {
               // do work!
          }
          start = get_current_time();
     }
     uint64_t elapsed = get_current_time() - start;
     if(elapsed > timeout) {
          break;
     }
     sleep(10);
}
于 2012-08-16T18:19:51.013 回答
0

while ((bytes_read = CFReadStreamRead(stream, buffer, read_size)) > 0) {
// 工作!
}

我不认为这段代码有什么特别之处。CFReadStreamRead 在内部以类似的方式实现。引用 Apple 的文档:“这个函数会阻塞,直到至少有一个字节可用;它不会阻塞,直到缓冲区被填满。”

于 2013-11-19T12:25:58.203 回答
0

我设置了一个自定义超时方法:

var hasRecievedUpdate = false
var httpStream: CFReadStream?
var handler: ((Data?, URLResponse?, Error?) -> Void)?

func send() {
        let stream = httpStream as Stream
        stream.delegate = self

        stream.schedule(in: RunLoop.current, forMode: RunLoop.Mode.default)
        stream.open()

        hasRecievedUpdate = false

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + self.timeout) {
            if !self.hasRecievedUpdate
            {
                stream.close()
                self.handler?(nil, nil, nil)
            }
        }
}

 func stream(_ aStream: Stream, handle eventCode: Stream.Event) {

        self.hasRecievedUpdate = true
        ...
}
于 2019-05-28T21:16:58.593 回答