CFNetwork Persistent Connection (Keep alives)

4k Views Asked by At

I am trying to reduce our server overheads by using persistent HTTP connections via the Apple CFNetwork framework. However there is little documentation about it. The only information I could find suggested that the framework recycles streams on behalf of the developer as long as the appropriate flags are set:

        CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, methodString, url, kCFHTTPVersion1_1);
        CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Keep-Alive"), CFSTR("120")); <--- This line

        //Set message body if we're posting
        if (msDetails.eType == HttpRequestDetails::POST)
        {
            CFDataRef bodyRef = CFDataCreate(kCFAllocatorDefault, (const UInt8*)msDetails.strBody.c_str(), msDetails.strBody.length());
            CFHTTPMessageSetBody(request, bodyRef);
            CFRelease(bodyRef); 
        }

        //Create the read stream...
        CFReadStreamRef ReadStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);

        //...use persistent connections..
        CFReadStreamSetProperty(ReadStream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue); <--- This line

        //...enable SSL if the URL is https
        if(msDetails.strURL[4] == 's')
        {
            //Hey an https request
            CFMutableDictionaryRef pDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
            CFDictionarySetValue(pDict, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
            CFDictionarySetValue(pDict, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelSSLv3);
            CFReadStreamSetProperty(ReadStream, kCFStreamPropertySSLSettings, pDict);
            CFRelease(pDict);
        }

        CFReadStreamOpen(ReadStream);

The above code causes a "CFNetwork internal error". If I remove the CFReadStreamSetProperty(ReadStream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue) call then I no longer receive the error. It is also worth mentioning that I close the readstream once I have finished reading the data, but maybe I need to manage the stream pool myself?

Does anyone have any documentation, examples or tutorials they can refer me to? I'm keen to keep using the CFNetwork stuff as we have a client that insists we must minimize our use of Obj-C.

2

There are 2 best solutions below

1
On

add CFNetwork.framework

and #import <CFNetwork/CFHTTPStream.h>

0
On

I've been struggling with the same thing.

It seems the key is to make sure all the stream settings are exactly the same for the requests. In particular, you have to pass in the EXACT same dictionary object to kCFStreamPropertySSLSettings for all the requests. It isn't enough that they have the same contents, you have to re-use the exact same dictionary.