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);
相關文章
相關標籤/搜索