我有在 iOS 上使用 CFReadStreamRead 的旧代码,但如果没有/丢失连接,CFReadStreamRead 将永远阻塞。如何将 CFReadStreamRead 设置为超时?
提前致谢
我有在 iOS 上使用 CFReadStreamRead 的旧代码,但如果没有/丢失连接,CFReadStreamRead 将永远阻塞。如何将 CFReadStreamRead 设置为超时?
提前致谢
@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");
}
}
谢谢!
我最终使用了一个自制的超时。代码是这样的:
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);
}
while ((bytes_read = CFReadStreamRead(stream, buffer, read_size)) > 0) {
// 工作!
}
我不认为这段代码有什么特别之处。CFReadStreamRead 在内部以类似的方式实现。引用 Apple 的文档:“这个函数会阻塞,直到至少有一个字节可用;它不会阻塞,直到缓冲区被填满。”
我设置了一个自定义超时方法:
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
...
}