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);
}
カスタムタイムアウトメソッドを設定しました:
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
...
}