1.CFHTTP
可以使用CFHTTP API建立HTTP請求,通常HTTP要求方法包括GET、HEAD、PUT、POST、DELETE、TRACR、CONNECT和OPTIONS。使用CFHTTP請求一般4個步驟:
- 使用CFHTTPMessageCreateRequest函數產生一個CFHTTP訊息對象
- 使用CFHTTPMessageSetBody函數設定訊息內容
- 使用CFHTTPMessageSetHeaderFieldValue函數設定訊息頭
- 使用CFHTTPMessageCopySerializedMessage序列化訊息
只有http post 需要訊息內容,裡面是要提交的表單資料。
樣本:建立一個http get請求,序列化後的請求應該通過寫入流(write stream)發送。
CFStringRef requestHeader = CFSTR("Connection");
CFStringRef requestHeaderValue = CFSTR("close");
CFStringRef requestBody = CFSTR("");
CFStringRef url = CFSTR("http://www.baidu.com/");
CFStringRef requestMethod = CFSTR("GET");
CFURLRef requestURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, requestURL, kCFHTTPVersion1_1);
CFHTTPMessageSetBody(request, requestBody);
CFHTTPMessageSetHeaderFieldValue(request, requestHeader, requestHeaderValue);
CFDataRef serializedRequest = CFHTTPMessageCopySerializedMessage(request);
建立HTTP相應的步驟與建立請求的方法差不多,不同之處是用CFHTTPMessageCreateResponse函數代替CFHTTPMessageCreateRequest。
可以使用一個CFReadStream對象來序列化並發送CFHTTP請求。當使用CFReadStream對象時,開啟讀取流的同時訊息會被序列化並發送,這樣可以方便地擷取響應。如下:
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, requestURL, kCFHTTPVersion1_1);
CFHTTPMessageSetBody(request, requestBody);
CFHTTPMessageSetheaderFieldValue(request, requestHeader, requestHeaderValue);
CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
CFReadStreamOpen(readStream);
調用CFReadStreamCopyProperty 可以從讀取流擷取響應訊息,代碼如下:
CFHTTPMessageRef response = CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);
使用CFHTTPMessageCopyResponseStatusLine函數獲得完整的狀態行,如下:
CFStringRef statusLine = CFHTTPMessageCopyResponseStatusLine(response);
或者,使用CFHTTPMessageGetResponseStatusCode函數擷取狀態代碼,如下:
UInt32 errCode = CFHTTPMessageGetResponseStatusCode(response);
為了擷取返回的資料,可以使用CFReadStreamSetClient方法設定回呼函數,將readStream加到run loop中。在回呼函數將每次讀取的資料存起來(比如,有一個NSMutableData類型的變數data),讀完後處理資料,代碼如下:
if(kCFStreamEventHasBytesAvailable == eventType)
{
UInt8 buff[255];
int length = CFReadStreamRead(stream, buff, 254);
[data appendBytes:buff length:length];
if(kCFStreamEventEndEncountered == eventType)
{
//讀取已完成,處理讀取的資料
}
}
如果接收資料是中文字串,注意在建立NSString時選擇編碼,比如UTF8或GB2312編碼,如下所示:
NSString *string = [[NSString alloc] initWithData:data encoding:0x80000632];//GB2312編碼
當使用CFReadStreamCreateForHTTPRequest建立讀取流時,流的重新導向預設是被禁止的。如果請求串連被重新導向,會導致一個錯誤,它的狀態代碼為300~307。如果收到一個重新導向錯誤,需要關閉這個流,然後重新建立一個流,啟用重新導向並開啟流。如下:
CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
if(CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue) == false)
{
//出錯處理
}
CFReadStreamOpen(myReadStream);
2.CFFTP
CFFTP也使用CFReadStream來傳送FTP資料。使用CFReadStreamCreateWithFTPURL方法來建立FTP請求,這樣會同時建立一個CFReadStreamRef對象來讀取FTP伺服器發送的資料,代碼如下:
CFStringRef url = CFSTR("ftp://ftp.example.com/file.txt");
CFURLRef requestURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
CFReadStreamRef readStream = CFReadStreamCreateWithFTPURL(kCFAllocatorDefault, requestURL);
下一步,使用CFReadStreamSetClient方法設定回呼函數來讀取資料,然後把readStream加到程式的run loop中。
如果FTP需要使用使用者名稱和密碼認證,通過CFReadStreamSetProperty方法設定kCFStreamPropertyFTPUserName和kCFStreamPropertyFTPPassword屬性。
要將檔案下載到本地,可以使用CFWriteStreamCreateWithFile方法建立一個指向本地檔案的寫入流,將接收到的資料寫入。
上傳檔案和下載檔案差不多,只不過把讀取流和寫入流反過來用,使用CFWriteStreamCreateWithFTPURL方法建立寫入流,使用CFReadStreamCreateWithFile建立讀取流。
建立遠程目錄的方法與上傳檔案類似,只不過將CFURL對象設定一個路徑而不是檔案。
擷取目錄列表的方法與下載檔案類似,資料讀取到緩衝後使用CFFTPCreateParsedResourceListing,方法對讀取進行解析。
3.NSURLConnection
CFNetwork是比較底層的介面,雖然用起來比較靈活,但並不好用。多數程式僅僅需要建立簡單的請求來擷取互連網上的一個檔案,那麼使用NSURLConnection要更加方便,因為不用跟通訊端、流還有回呼函數打交道,取而代之的是更熟悉的委託機制。
建立一個NSURL對象:
NSNRL *url = [NSURL URLWithString:@"http://www.baidu.com/"];
NSURL對象是用來建立NSURLRequest對象的,如下:
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoadtimeoutInterval:60.0];
可選的緩衝策略有以下幾種。
(1)NSURLRequestUseProtocolCachePolicy:使用相關協議預設緩衝策略。
(2)NSURLRequestReloadIgnoringLocalCacheData: 無論本機快取是什麼,請求都要重新載入資料。
(3)NSURLRequestReloadIgnoringLocalAndRemoteCacheData:不僅要忽略本機快取,在協議允許的情況下也要忽略遠程代理或中介軟體的緩衝。
(4)NSURLRequestReturnCacheDataElseLoad:優先使用快取資料,緩衝不存在時再去載入請求。
(5)NSURLRequestReturnCacheDataDontLoad:只載入快取資料,緩衝中不存在時也不請求,可理解為離線模式。
(6)NSURLRequestReloadRevalidatingCacheData: 緩衝中的資料沒有到期時才載入緩衝中的資料,否則請求資料並重新整理緩衝。
建立完NSURLRequest對象後就可以建立NSURLConnection對象了,如下:
NSURLConnection *connection = [[NSRULConnection alloc] initWithRequest:request delegate:self];
這個是非同步呼叫,NSURLConnection會在後台發送請求,通過設定委託參數,有資料時會收到通知。由一些委託方法來處理串連是過程中的不同事件。
當服務主機有響應將要開始發送資料時,didReceiveResponse:方法會被調用。這裡可以做一些初始化的工作,比如有一個NSMutableData類型的data對象來儲存資料,在這裡可以把對象長度設為0,如下所示
-(void) connection:(NSURLConnection *)connection didReceiveRespose:(NSURLResonse *)response
{
[data setLength:0];
}
當接收到資料時,didReceiveData:方法會被調用。這裡可以把資料加到NSMutableData對象的後面,如下:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)incomingData
{
[data appendData:incomingData];
}
當資料載入完成時會調用connecitionDidFinshLoading:方法,處理傳入的資料。這裡以字串處理為例,樣本應用中傳入的可能是圖片或其他任何類型的對象。
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{ NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(string);[data release]; } 串連或傳送資料失敗時,didFailWithError方法會被調用,如下:- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{NSLog(@"query failed with error:%@", [error localizedDescription]);[data release];}