iOS开发之CFNetwork框架使用
一、引言
在iOS应用开发中,CFNetwork框架其实并不是非常常用的,相对NSURLSession框架而言,这是一个相对底层的网络工作框架。官方文档中的下图描述了CFNetwork在整个网络体系中的位置:
CFNetwork与CoreFoundation关系密切,其实基于CoreFoundation框架的,结构如下图所示:
本篇博客中不会过多的设计CoreFoundation框架中的内容,主要总结和介绍CFNetwork的相关内容与简单应用。
二、使用CFNetwork进行简单的网络请求
CFNetwork是使用C语言实现的一套网络访问框架,进行一个简单的网络请求示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| CFStringRef method = CFSTR("GET");
CFStringRef urlStr = CFSTR("http://www.baidu.com");
CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, method, url, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("key"), CFSTR("Value"));
CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
CFStreamClientContext ctxt = {0, (__bridge void *)(self), NULL, NULL, NULL};
CFReadStreamSetClient(readStream, kCFStreamEventHasBytesAvailable|kCFStreamEventEndEncountered|kCFStreamEventOpenCompleted|kCFStreamEventCanAcceptBytes|kCFStreamEventErrorOccurred, myCallBack, &ctxt);
CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
printf("%d",CFReadStreamOpen(readStream));
|
实现myCallBack回调函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void myCallBack (CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo){ if (type == kCFStreamEventHasBytesAvailable) { UInt8 buff [1024]; CFReadStreamRead(stream, buff, 1024); printf("%s",buff); }else if(type==kCFStreamEventOpenCompleted){ NSLog(@"open"); }else if (type==kCFStreamEventErrorOccurred){ NSLog(@"error:%@",CFErrorCopyDescription( CFReadStreamCopyError(stream))); }else if (type==kCFStreamEventCanAcceptBytes){ NSLog(@"kCFStreamEventCanAcceptBytes"); }else if(type==kCFStreamEventEndEncountered){ NSLog(@"end"); CFReadStreamClose(stream); CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); } }
|
上面演示了简单的GET请求,如果使用的请求方法为POST,则可以进行请求体的设置,上面示例代码中,CFStringRef、CFURLRef、CFReadStreamRef等相关的类为CoreFoundation框架中的,这里暂不深究,简单使用即可。后面我们将详细的探讨CFNetwork中相关类的使用。
三、CFHTTPMessageRef详解
在基于C的框架中,类对象都是使用结构体指针描述的,CFHTTPMessageRef是HTTP消息的封装,其可以是一个HTTP请求,也可以是一个HTTP回执。与其相关的方法解析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| CFTypeID CFHTTPMessageGetTypeID(void);
CFHTTPMessageRef CFHTTPMessageCreateRequest(CFAllocatorRef __nullable alloc, CFStringRef requestMethod, CFURLRef url, CFStringRef httpVersion);
CFHTTPMessageRef CFHTTPMessageCreateResponse(CFAllocatorRef __nullable alloc,CFIndex statusCode,CFStringRef __nullable statusDescription,CFStringRef httpVersion);
CFHTTPMessageRef CFHTTPMessageCreateEmpty(CFAllocatorRef __nullable alloc, Boolean isRequest);
CFHTTPMessageRef CFHTTPMessageCreateCopy(CFAllocatorRef __nullable alloc, CFHTTPMessageRef message);
Boolean CFHTTPMessageIsRequest(CFHTTPMessageRef message);
CFStringRef CFHTTPMessageCopyVersion(CFHTTPMessageRef message);
CFDataRef CFHTTPMessageCopyBody(CFHTTPMessageRef message);
void CFHTTPMessageSetBody(CFHTTPMessageRef message, CFDataRef bodyData);
CFStringRef CFHTTPMessageCopyHeaderFieldValue(CFHTTPMessageRef message, CFStringRef headerField);
CFDictionaryRef CFHTTPMessageCopyAllHeaderFields(CFHTTPMessageRef message);
void CFHTTPMessageSetHeaderFieldValue(CFHTTPMessageRef message, CFStringRef headerField, CFStringRef __nullable value);
Boolean CFHTTPMessageAppendBytes(CFHTTPMessageRef message, const UInt8 *newBytes, CFIndex numBytes);
Boolean CFHTTPMessageIsHeaderComplete(CFHTTPMessageRef message);
CFDataRef CFHTTPMessageCopySerializedMessage(CFHTTPMessageRef message);
CFURLRef CFHTTPMessageCopyRequestURL(CFHTTPMessageRef request);
CFStringRef CFHTTPMessageCopyRequestMethod(CFHTTPMessageRef request);
Boolean CFHTTPMessageAddAuthentication(CFHTTPMessageRef request,CFHTTPMessageRef __nullable authenticationFailureResponse,CFStringRef username,CFStringRef password,CFStringRef __nullable authenticationScheme,Boolean forProxy);
CFIndex CFHTTPMessageGetResponseStatusCode(CFHTTPMessageRef response);
CFStringRef CFHTTPMessageCopyResponseStatusLine(CFHTTPMessageRef response);
|
四、进行请求与回调处理
CFHTTPMessageRef的主要用途是构建出HTTP的请求或回执对象,请求的相关发起与回调方法都封装在CFHTTPStream.h这个头文件中,解析如下:
1 2 3 4 5 6
| CFReadStreamRef CFReadStreamCreateForHTTPRequest(CFAllocatorRef __nullable alloc, CFHTTPMessageRef request);
CFReadStreamRef CFReadStreamCreateForStreamedHTTPRequest(CFAllocatorRef __nullable alloc, CFHTTPMessageRef requestHeaders, CFReadStreamRef requestBody);
void CFHTTPReadStreamSetRedirectsAutomatically(CFReadStreamRef httpStream, Boolean shouldAutoRedirect);
|
五、关于请求的证书验证
有时,客户端在向服务端进行请求时收到状态为401的回执,这时往往表明需要客户端提供用户凭证,在CFNetWork框架中,用户凭证与证书验证相关方法封装在CFHTTPAuthentication.h头文件中。解析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| CFTypeID CFHTTPAuthenticationGetTypeID(void);
CFHTTPAuthenticationRef CFHTTPAuthenticationCreateFromResponse(CFAllocatorRef __nullable alloc, CFHTTPMessageRef response);
Boolean CFHTTPAuthenticationIsValid(CFHTTPAuthenticationRef auth, CFStreamError * __nullable error);
Boolean CFHTTPAuthenticationAppliesToRequest(CFHTTPAuthenticationRef auth, CFHTTPMessageRef request);
Boolean CFHTTPAuthenticationRequiresOrderedRequests(CFHTTPAuthenticationRef auth);
Boolean CFHTTPMessageApplyCredentials(CFHTTPMessageRef request,CFHTTPAuthenticationRef auth,CFStringRef __nullable username,CFStringRef __nullable password,CFStreamError * __nullable error);
Boolean CFHTTPMessageApplyCredentialDictionary(CFHTTPMessageRef request,CFHTTPAuthenticationRef auth,CFDictionaryRef dict,CFStreamError * __nullable error);
CFStringRef CFHTTPAuthenticationCopyRealm(CFHTTPAuthenticationRef auth);
CFArrayRef CFHTTPAuthenticationCopyDomains(CFHTTPAuthenticationRef auth);
CFStringRef CFHTTPAuthenticationCopyMethod(CFHTTPAuthenticationRef auth);
Boolean CFHTTPAuthenticationRequiresUserNameAndPassword(CFHTTPAuthenticationRef auth);
Boolean CFHTTPAuthenticationRequiresAccountDomain(CFHTTPAuthenticationRef auth);
|
六、进行FTP协议的数据交换
CFNetWork框架也支持与FTP协议的服务端进行数据交互,方法解析如下:
1 2 3 4 5 6
| CFReadStreamRef CFReadStreamCreateWithFTPURL(CFAllocatorRef __nullable alloc, CFURLRef ftpURL);
CFIndex CFFTPCreateParsedResourceListing(CFAllocatorRef __nullable alloc, const UInt8 *buffer, CFIndex bufferLength, CFDictionaryRef __nullable * __nullable parsed);
CFWriteStreamRef CFWriteStreamCreateWithFTPURL(CFAllocatorRef __nullable alloc, CFURLRef ftpURL);
|
对于FTP写入和读取流来说,可以使用CFReadStreamSetProperty()函数或者CFWriteStreamSetProperty()函数来进行属性的设置,可设置的属性列举如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| kCFStreamPropertyFTPUserName kCFStreamPropertyFTPPassword kCFStreamPropertyFTPUsePassiveMode kCFStreamPropertyFTPResourceSize kCFStreamPropertyFTPFileTransferOffset kCFStreamPropertyFTPAttemptPersistentConnection kCFStreamPropertyFTPProxy kCFStreamPropertyFTPFetchResourceInfo
kCFStreamPropertyFTPProxyHost kCFStreamPropertyFTPProxyPort kCFStreamPropertyFTPProxyUser kCFStreamPropertyFTPProxyPassword
kCFFTPResourceMode kCFFTPResourceName kCFFTPResourceOwne kCFFTPResourceGroup kCFFTPResourceLink kCFFTPResourceSize kCFFTPResourceType kCFFTPResourceModDate
|
七、主机地址相关操作
CFNetWork中也封装了与主机地址域名相关的操作方法,例如,我们可以通过域名进行DNS解析出IP地址,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11
| #import <netinet/in.h> #import <arpa/inet.h> CFStringRef hostString = CFSTR("www.baidu.com"); CFHostRef host = CFHostCreateWithName(CFAllocatorGetDefault(), hostString); CFHostStartInfoResolution(host, kCFHostAddresses, NULL); CFArrayRef addresses = CFHostGetAddressing(host, NULL); for (int i = 0; i<CFArrayGetCount(addresses); i++) { struct sockaddr_in * ip; ip = (struct sockaddr_in *)CFDataGetBytePtr(CFArrayGetValueAtIndex(addresses, i)); printf("%s\n",inet_ntoa(ip->sin_addr)); }
|
CFHostRef对象操作相关方法解析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| CFTypeID CFHostGetTypeID(void);
CFHostRef CFHostCreateWithName(CFAllocatorRef __nullable allocator, CFStringRef hostname);
CFHostRef CFHostCreateWithAddress(CFAllocatorRef __nullable allocator, CFDataRef addr);
CFHostRef CFHostCreateCopy(CFAllocatorRef __nullable alloc, CFHostRef host);
Boolean CFHostStartInfoResolution(CFHostRef theHost, CFHostInfoType info, CFStreamError * __nullable error);
CFArrayRef CFHostGetAddressing(CFHostRef theHost, Boolean * __nullable hasBeenResolved);
CFArrayRef CFHostGetNames(CFHostRef theHost, Boolean * __nullable hasBeenResolved);
CFDataRef CFHostGetReachability(CFHostRef theHost, Boolean * __nullable hasBeenResolved);
void CFHostCancelInfoResolution(CFHostRef theHost, CFHostInfoType info);
Boolean CFHostSetClient(CFHostRef theHost, CFHostClientCallBack __nullable clientCB, CFHostClientContext * __nullable clientContext);
void CFHostScheduleWithRunLoop(CFHostRef theHost, CFRunLoopRef runLoop, CFStringRef runLoopMode);
void CFHostUnscheduleFromRunLoop(CFHostRef theHost, CFRunLoopRef runLoop, CFStringRef runLoopMode);
|
八、后续
上面介绍的内容更多还是关于使用CFNetWork框架进行HTTP或FTP请求的相关方法,其实CFNetWork框架中还提供了复杂的Bonjour服务功能,其与CFNetService相关,这部分内容后面有时间再进行整理总结吧。
欢迎交流 珲少 QQ 316045346