IOS学习之 CoreFoundation框架的CFNetwork

转载自     http://blog.csdn.net/kesalin/article/details/8798039 git

                http://blog.csdn.net/kesalin/article/details/8801156github


1. iOS网络编程层次结构也分为三层:编程

  • Cocoa层:NSURL,Bonjour,Game Kit,WebKit网络

  • Core Foundation层:基于 C 的 CFNetwork 和 CFNetServices异步

  • OS层:基于 C 的 BSD socketsocket

Cocoa层是最上层的基于 Objective-C 的 API,好比 URL访问,NSStream,Bonjour,GameKit等,这是大多数状况下咱们经常使用的 API。Cocoa 层是基于 Core Foundation 实现的。ide

Core Foundation层:由于直接使用 socket 须要更多的编程工做,因此苹果对 OS 层的 socket 进行简单的封装以简化编程任务。该层提供了 CFNetwork 和 CFNetServices,其中 CFNetwork 又是基于 CFStream 和 CFSocket函数

OS层:最底层的 BSD socket 提供了对网络编程最大程度的控制,可是编程工做也是最多的。所以,苹果建议咱们使用 Core Foundation 及以上层的 API 进行编程。oop


实际项目中,常使用成熟的第三方网络库:spa

(1)ASIHTTPRequest,中止更新,应该放弃。

(2)AFNetworking,轻量级。项目源码: https://github.com/AFNetworking/AFNetworking


2. CFNetwork API 简介

CFNetwork 接口是基于 C 的,下面的接口用于建立一对 socket stream,一个用于读取,一个用于写入:

void CFStreamCreatePairWithSocketToHost(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream);

该函数使用 host 以及 port,CFNetwork 会将该 host 转换为 IP 地址,并转换为网络字节顺序。若是咱们只须要一个 socket stream,咱们能够将另一个设置为 NULL。还有另外两个“重载”的建立 socket sream的接口:CFStreamCreatePairWithSocket 和 CFStreamCreatePairWithPeerSocketSignature,在这里就不一一介绍了。

注意:在使用这些 socket stream 以前,必须显式地调用其 open 函数:

Boolean CFReadStreamOpen(CFReadStreamRef stream);
Boolean CFWriteStreamOpen(CFWriteStreamRef stream);

但与 socket 不一样的是,这两个接口是异步的,当成功 open 以后,若是调用方设置了获取 kCFStreamEventOpenCompleted 事件的标志的话就会其调用回调函数。


而该回调函数及其参数设置是经过以下接口进行的:

Boolean CFReadStreamSetClient(CFReadStreamRef stream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext);
Boolean CFWriteStreamSetClient(CFWriteStreamRef stream, CFOptionFlags streamEvents, CFWriteStreamClientCallBack clientCB, CFStreamClientContext *clientContext);

该函数用于设置回调函数及相关参数。经过 streamEvents 标志来设置咱们对哪些事件感兴趣;clientCB 是一个回调函数,当事件标志对应的事件发生时,该回调函数就会被调用;clientContext 是用于传递参数到回调函数中去。

当设置好回调函数以后,咱们能够将 socket stream 当作事件源调度到 run-loop 中去,这样 run-loop 就能分发该 socket stream 的网络事件了。

void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode);
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode);

注意,在咱们再也不关心该 socket stream 的网络事件时,记得要调用以下接口将 socket stream 从 run-loop 的事件源中移除。

void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode);
void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode);

当咱们将 socket stream 的网络事件调度到 run-loop 以后,咱们就能在回调函数中相应各类事件,好比 kCFStreamEventHasBytesAvailable 读取数据:

Boolean CFReadStreamHasBytesAvailable(CFReadStreamRef stream);
CFIndex CFReadStreamRead(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength);

或 kCFStreamEventCanAcceptBytes 写入数据:

Boolean CFWriteStreamCanAcceptBytes(CFWriteStreamRef stream);
CFIndex CFWriteStreamWrite(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength);

最后,咱们调用 close 方法关闭 socket stream:

void CFReadStreamClose(CFReadStreamRef stream);
void CFWriteStreamClose(CFWriteStreamRef stream);
相关文章
相关标签/搜索