在iOS应用开发中,CFNetwork框架其实并非很是经常使用的,相对NSURLSession框架而言,这是一个相对底层的网络工做框架。官方文档中的下图描述了CFNetwork在整个网络体系中的位置:数组
CFNetwork与CoreFoundation关系密切,其实基于CoreFoundation框架的,结构以下图所示:网络
本篇博客中不会过多的设计CoreFoundation框架中的内容,主要总结和介绍CFNetwork的相关内容与简单应用。框架
CFNetwork是使用C语言实现的一套网络访问框架,进行一个简单的网络请求示例代码以下:函数
//建立请求方法字符串 CFStringRef method = CFSTR("GET"); //建立请求URL字符串 CFStringRef urlStr = CFSTR("http://www.baidu.com"); //建立请求URL对象 CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL); //建立HTTP消息对象 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); //将读取流加入runloop中 CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); //开启流 printf("%d",CFReadStreamOpen(readStream));
实现myCallBack回调函数以下:oop
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); //将流从runloop中移除 CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); } }
上面演示了简单的GET请求,若是使用的请求方法为POST,则能够进行请求体的设置,上面示例代码中,CFStringRef、CFURLRef、CFReadStreamRef等相关的类为CoreFoundation框架中的,这里暂不深究,简单使用便可。后面咱们将详细的探讨CFNetwork中相关类的使用。ui
在基于C的框架中,类对象都是使用结构体指针描述的,CFHTTPMessageRef是HTTP消息的封装,其能够是一个HTTP请求,也能够是一个HTTP回执。与其相关的方法解析以下:url
//返回CGHTTPMessageRef的类型ID CFTypeID CFHTTPMessageGetTypeID(void); //建立一个HTTP请求消息 /* alloc为内存管理器 通常使用默认的kCFAllocatorDefault requestMethod为请求方法 url为请求的路径 httpVersion为请求的HTTP版本 HTTP版本定义以下: kCFHTTPVersion1_0 kCFHTTPVersion1_1 kCFHTTPVersion2_0 */ CFHTTPMessageRef CFHTTPMessageCreateRequest(CFAllocatorRef __nullable alloc, CFStringRef requestMethod, CFURLRef url, CFStringRef httpVersion); //建立一个HTTP回执消息 /* alloc内存管理器 statusCode 请求回执状态码 statusDescription 请求回执状态描述 httpVersion HTTP版本号 */ CFHTTPMessageRef CFHTTPMessageCreateResponse(CFAllocatorRef __nullable alloc,CFIndex statusCode,CFStringRef __nullable statusDescription,CFStringRef httpVersion); //建立一个空的HTTP消息 /* isRequest 若是传入kCFBooleanTrue 则为请求类型 不然为回执类型 */ CFHTTPMessageRef CFHTTPMessageCreateEmpty(CFAllocatorRef __nullable alloc, Boolean isRequest); //复制一个HTTP消息 CFHTTPMessageRef CFHTTPMessageCreateCopy(CFAllocatorRef __nullable alloc, CFHTTPMessageRef message); //判断一个HTTP消息是请求 仍是 回执 Boolean CFHTTPMessageIsRequest(CFHTTPMessageRef message); //获取HTTP版本 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); /*=================下面这些方法针对于请求类型的消息=====================*/ //获取消息中的url 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这个头文件中,解析以下:spa
//经过一个HTTP请求建立一个读取流对象 CFReadStreamRef CFReadStreamCreateForHTTPRequest(CFAllocatorRef __nullable alloc, CFHTTPMessageRef request); //经过一个HTTP请求建立读取流对象 可是请求的body会被忽略 取requestBody做为请求体 CFReadStreamRef CFReadStreamCreateForStreamedHTTPRequest(CFAllocatorRef __nullable alloc, CFHTTPMessageRef requestHeaders, CFReadStreamRef requestBody); //设置读取流是否自动重定向 void CFHTTPReadStreamSetRedirectsAutomatically(CFReadStreamRef httpStream, Boolean shouldAutoRedirect);
有时,客户端在向服务端进行请求时收到状态为401的回执,这时每每代表须要客户端提供用户凭证,在CFNetWork框架中,用户凭证与证书验证相关方法封装在CFHTTPAuthentication.h头文件中。解析以下:设计
//获取CFHTTPAuthentication类ID CFTypeID CFHTTPAuthenticationGetTypeID(void); /* 经过一个401或者407的请求回执建立一个 用户认证对象 */ 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); /* 此方法和上面方法做用一致 不一样的是使用字典来进行用户名和密码的设置 字段的键以下: kCFHTTPAuthenticationUsername 用户名键 kCFHTTPAuthenticationPassword 密码键 kCFHTTPAuthenticationAccountDomain 帐户域 */ 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);
CFNetWork框架也支持与FTP协议的服务端进行数据交互,方法解析以下:代理
//根据URL建立FTP读取流对象 用来进行文件下载 CFReadStreamRef CFReadStreamCreateWithFTPURL(CFAllocatorRef __nullable alloc, CFURLRef ftpURL); //解析文件或目录的格式化数据 CFIndex CFFTPCreateParsedResourceListing(CFAllocatorRef __nullable alloc, const UInt8 *buffer, CFIndex bufferLength, CFDictionaryRef __nullable * __nullable parsed); //根据URL建立一个FTP写入流对象 用来进行文件上传 CFWriteStreamRef CFWriteStreamCreateWithFTPURL(CFAllocatorRef __nullable alloc, CFURLRef ftpURL);
对于FTP写入和读取流来讲,可使用CFReadStreamSetProperty()函数或者CFWriteStreamSetProperty()函数来进行属性的设置,可设置的属性列举以下:
kCFStreamPropertyFTPUserName //设置用户名 kCFStreamPropertyFTPPassword //设置密码 kCFStreamPropertyFTPUsePassiveMode //布尔值 设置是否被动模式 kCFStreamPropertyFTPResourceSize //资源大小 kCFStreamPropertyFTPFileTransferOffset //记录文件位置 用来断点续传 kCFStreamPropertyFTPAttemptPersistentConnection //是否重用链接 kCFStreamPropertyFTPProxy //设置代理字典 kCFStreamPropertyFTPFetchResourceInfo //资源详情字典 //下面为代理字典中能够定义的键 kCFStreamPropertyFTPProxyHost //代理主机 kCFStreamPropertyFTPProxyPort //代理端口 kCFStreamPropertyFTPProxyUser //代理用户名 kCFStreamPropertyFTPProxyPassword //代理密码 //下面是资源详情字典中能够定义的键 kCFFTPResourceMode //资源模式 kCFFTPResourceName //资源名 kCFFTPResourceOwne //资源全部者 kCFFTPResourceGroup //资源组 kCFFTPResourceLink //资源连接 kCFFTPResourceSize //资源尺寸 kCFFTPResourceType //资源类型 kCFFTPResourceModDate //修改时间
CFNetWork中也封装了与主机地址域名相关的操做方法,例如,咱们能够经过域名进行DNS解析出IP地址,示例代码以下:
#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对象操做相关方法解析以下:
//获取类型ID CFTypeID CFHostGetTypeID(void); //根据域名建立CFHostRef对象 CFHostRef CFHostCreateWithName(CFAllocatorRef __nullable allocator, CFStringRef hostname); /* 根据地址建立CFHostRef对象 addr参数为sockaddr结构体数据 */ CFHostRef CFHostCreateWithAddress(CFAllocatorRef __nullable allocator, CFDataRef addr); //CFHostRef对象的复制 CFHostRef CFHostCreateCopy(CFAllocatorRef __nullable alloc, CFHostRef host); //对指定主机进行信息预查找 返回值标明是否查找成功 Boolean CFHostStartInfoResolution(CFHostRef theHost, CFHostInfoType info, CFStreamError * __nullable error); //获取主机的地址列表 数组中为sockaddr结构体数据 CFArrayRef CFHostGetAddressing(CFHostRef theHost, Boolean * __nullable hasBeenResolved); //获取主机名列表 CFArrayRef CFHostGetNames(CFHostRef theHost, Boolean * __nullable hasBeenResolved); //获取主机可达性信息 CFDataRef CFHostGetReachability(CFHostRef theHost, Boolean * __nullable hasBeenResolved); //取消未完成的解析 /* 解析类型枚举 typedef CF_ENUM(int, CFHostInfoType) { //地址 kCFHostAddresses = 0, //主机名 kCFHostNames = 1, //可达性信息 kCFHostReachability = 2 }; */ void CFHostCancelInfoResolution(CFHostRef theHost, CFHostInfoType info); //设置客户端回调 Boolean CFHostSetClient(CFHostRef theHost, CFHostClientCallBack __nullable clientCB, CFHostClientContext * __nullable clientContext); //注册进Runloop void CFHostScheduleWithRunLoop(CFHostRef theHost, CFRunLoopRef runLoop, CFStringRef runLoopMode); //从Runloop中注销 void CFHostUnscheduleFromRunLoop(CFHostRef theHost, CFRunLoopRef runLoop, CFStringRef runLoopMode);
上面介绍的内容更多仍是关于使用CFNetWork框架进行HTTP或FTP请求的相关方法,其实CFNetWork框架中还提供了复杂的Bonjour服务功能,其与CFNetService相关,这部份内容后面有时间再进行整理总结吧。
欢迎交流 珲少 QQ 316045346