Frage

I have legacy code using CFReadStreamRead on the iOS, but if there is no/loss of a connection CFReadStreamRead will block forever. How do I setup CFReadStreamRead to timeout?

Thanks in advance

War es hilfreich?

Lösung 2

I ended up using a home grown timeout. The code was something like this:

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);
}

Andere Tipps

@Michael Wildermuth Yes, there was an error on opening the stream and got it fixed. Someone who face the same issue, the below code would help.

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);

And for the callback function,

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");
}

}

Thanks!

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

I don't think this code achieves anything special. CFReadStreamRead is internally implemented in a similar manner. Quoting Apple's documentation on this: "This function blocks until at least one byte is available; it does not block until buffer is filled."

I set a custom timeout method:

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
        ...
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top