天天看點

iOS 網絡程式設計模式總結

       IOS 能夠採用三類api 接口進行網絡程式設計,依據抽象層次從低到高分别為socket方式、stream方式、url 方式。

一 、socket 方式

       IOS 提供的socket 方式的網絡程式設計接口為CFSocket。CFSocket是BSD sockets的抽象和封裝,CFSocket提供BSD sockets差點兒全部的功能,并與run loop內建。用來實作多線程網絡程式設計和網絡事件監聽。基于 CFSocket能夠實作各種類型的 socket程式設計,包含stream-based 的sockets(如tcp)和packet-based 的sockets(如udp)。須要注意的是在iOS中CFSocket接口在須要時不自己主動激活裝置的 cellular modem或on-demand VPN。

      CFSocket包含下面程式設計接口,包含Socket的 建立、配置。以及依據建立和配置好的Socket 進行 遠端通訊等接口。

1  Socket的 建立

1 .1、CFSocketCreate 建立一個特定協定和類型的 CFSocket對象 1.2、CFSocketCreateWithSocketSignature 該接口依據一個包含通訊協定和位址的CFSocketSignature結構來建立一個CFSocket對象 1.3、 CFSocketCreateConnectedToSocketSignature 該接口在建立一個CFSocket對象的同一時候還與一個遠端主機進行連接配接。 1.4、CFSocketCreateWithNative 該接口通過封裝一個存在的 BSD socket來建立一個CFSocket對象。

2   Socket的配置

2.1   CFSocketCopyAddress 功能: 傳回一個 CFSocket對象的本地位址。 文法: SWIFT func CFSocketCopyAddress(_ s: CFSocket!) -> CFData! 2.2、CFSocketCopyPeerAddress 功能:傳回與一個 CFSocket對象連接配接的遠端位址。 func CFSocketCopyPeerAddress(_ s: CFSocket!) -> CFData! 2.3  CFSocketDisableCallBacks 功能:暫時取消一個CFSocket對象建立時指定的某種類型的事件回調。 func CFSocketDisableCallBacks(_ s: CFSocket!,                             _ callBackTypes: CFOptionFlags) 2.4   CFSocketEnableCallBacks 功能:又一次同意先前CFSocketDisableCallBacks函數取消的某種類型的事件回調。 func CFSocketEnableCallBacks(_ s: CFSocket!,                            _ callBackTypes: CFOptionFlags) 2.5 CFSocketGetContext 功能:傳回一個CFSocket對象的上下文資訊。 func CFSocketGetContext(_ s: CFSocket!,                       _ context: UnsafeMutablePointer<CFSocketContext>) 2.6 CFSocketGetNative 傳回與一個CFSocket對象相關的本地 BSD socket。 func CFSocketGetNative(_ s: CFSocket!) -> CFSocketNativeHandle 2.7   CFSocketGetSocketFlags 功能:傳回控制一個CFSocket對象的确定行為的 标志。 func CFSocketGetSocketFlags(_ s: CFSocket!) -> CFOptionFlags 2.8 CFSocketSetSocketFlags 功能:設定控制一個CFSocket對象的确定行為的 标志。 func CFSocketSetSocketFlags(_ s: CFSocket!,                           _ flags: CFOptionFlags) 2.9 CFSocketSetAddress func CFSocketSetAddress(_ s: CFSocket!,                       _ address: CFData!) -> CFSocketError 功能:為一個CFSocket對象綁定一個本地位址并在本地socket支援的情況下對socket進行配置使其處于監聽狀态。該函數相應本地socket的 bind以及listen功能。 一旦CFSocket對象綁定位址。依賴于socket的協定,其他程序和主機能連接配接到該CFSocket對象。

3、Sockets的使用

3.1 CFSocketConnectToAddress 功能:打開與一個遠端socket的一個連接配接。 func CFSocketConnectToAddress(_ s: CFSocket!,                             _ address: CFData!,                             _ timeout: CFTimeInterval) -> CFSocketError 3.2 CFSocketCreateRunLoopSource func CFSocketCreateRunLoopSource(_ allocator: CFAllocator!,                                _ s: CFSocket!,                                _ order: CFIndex) -> CFRunLoopSource! 功能:為一個CFSocket對象建立一個CFRunLoopSource對象。該建立的 CFRunLoopSource對象不自己主動加入到一個run loop。為了添加該run loop source到某個run loop。須要調用CFRunLoop對象 的CFRunLoopAddSource函數來為該CFRunLoop對象加入run loop source。 3.3 CFSocketGetTypeID 功能:傳回CFSocket對象的 opaque類型相應的類型标示符。 func CFSocketGetTypeID() -> CFTypeID  3.4  CFSocketInvalidate 功能:使一個CFSocket對象無效,使其停止接收和發送不論什麼消息。 func CFSocketInvalidate(_ s: CFSocket!) 3.5 CFSocketIsValid 功能:傳回一個訓示一個CFSocket對象是否有效及能否夠發送和接收消息的布爾值。 func CFSocketIsValid(_ s: CFSocket!) -> Boolean 3.6 CFSocketSendData 功能:該函數用來通過一個CFSocket對象發送資料。 func CFSocketSendData(_ s: CFSocket!,                     _ address: CFData!,                     _ data: CFData!,                     _ timeout: CFTimeInterval) -> CFSocketError

二、stream程式設計模式

       stream程式設計模式提供了與 unix 的檔案操作類似的模式。首先建立和設定流。接着打開流,然後讀寫流,在流存在時還能夠通過查詢流的相關屬性來讀取流的相關資訊。在流使用完畢後關閉流。

       iOS 為stream程式設計模式提供的api程式設計接口包含兩大類,一類是Core Foundation架構層用C語言實作的CFStream  API(包含CFStream、 CFReadStream 、CFWriteStream等),一類是基于其上的在Foundation架構層用Objective-C語言實作的NSStream API(包含NSStream、NSInputStream NSOutputStream等),兩者提供類似的接口和行為。當中某些對象是toll-free bridged類型的。如CFStream 與NSStream。CFReadStream與NSInputStream。CFWriteStream與NSOutputStream之間,是以能夠混合使用。

       開發者能夠依據自己的語言偏好選擇使用。

       CFStream API的主要接口:

1、CFStream 建立接口

1.1  CFStreamCreatePairWithPeerSocketSignature

          功能:建立一對到一個socket的可讀和可寫流。

1.2 CFStreamCreatePairWithSocketToHost 功能:建立連接配接到一個特定主機的特定port的一對可讀寫流。 1.3 CFStreamCreatePairWithSocket 功能:建立一對連接配接到一個socket的可讀寫流 1.4 CFStreamCreateBoundPair 功能:建立一對讀寫流。 其他可讀寫流建立接口:  1.5 CFReadStreamCreateForHTTPRequest    功能:為一個CFHTTP請求建立一個可讀流。 1.6 CFReadStreamCreateForStreamedHTTPRequest 功能:為一個HTTP請求的body保持在記憶體的CFHTTP請求建立一個可讀流。 1.7  CFReadStreamCreateWithFTPURL 功能:建立一個FTP可讀流 1.8  CFWriteStreamCreateWithFTPURL

2. CFReadStream接口

2.1 流的打開和關閉       CFReadStreamOpen

       CFReadStreamClose

2.2  讀取資料

      CFReadStreamRead

2.3.  排程一個可讀流

  CFReadStreamScheduleWithRunLoop(_:_:_:) 

           CFReadStreamUnscheduleFromRunLoop(_:_:_:) 

2.4 檢查可讀流的屬性  

CFReadStreamCopyProperty(_:_:)  CFReadStreamGetBuffer(_:_:_:)  CFReadStreamCopyError(_:)  CFReadStreamGetError(_:)  CFReadStreamGetStatus(_:)  CFReadStreamHasBytesAvailable(_:) 

2.5 設定可讀流的屬性

CFReadStreamSetClient(_:_:_:_:) CFReadStreamSetProperty(_:_:_:) 

 2.6 得到 CFReadStream的 Type ID

                    CFReadStreamGetTypeID()

3.CFWriteStream 相關接口

     3.1 CFWriteStreamClose(_:)      3.2 CFWriteStreamOpen(_:)       3.3 CFWriteStreamWrite(_:_:_:)

        3.4 CFWriteStreamScheduleWithRunLoop(_:_:_:)

  3.5 CFWriteStreamUnscheduleFromRunLoop(_:_:_:)

        3.6 CFWriteStreamCanAcceptBytes(_:)

      3.7 CFWriteStreamCopyProperty(_:_:)       3.8 CFWriteStreamCopyError(_:)       3.9 CFWriteStreamGetError(_:)       3.10 CFWriteStreamGetStatus(_:) 

         3.11 CFWriteStreamSetClient(_:_:_:_:)

  3.12 CFWriteStreamSetProperty(_:_:_:)        3.13 CFWriteStreamGetTypeID()

CFStream API的使用步驟:

1) 利用流建立接口建立相關流; 2)、調用CFReadStreamSetClient (可讀流)或CFWriteStreamSetClient (可寫流)來登記要接收的流相關的事件; 3)、調用CFReadStreamScheduleWithRunLoop(可讀流)或CFWriteStreamScheduleWithRunLoop(可寫流)來使在流在一個run loop上進行排程以便接收相關事件; 4)、調用CFReadStreamOpen 或CFWriteStreamOpen 來打開已建立的流。 5)、在讀取流的建立時登記的回調中,在接收到kCFStreamEventHasBytesAvailable事件時來讀取資料。 在可寫流已登記的回調中,在接收到kCFStreamEventCanAcceptBytes 事件時開始發送資料或請求; 6) 傳輸資料完畢,關閉和釋放打開和建立的相關流。

2、NSStream   API的使用

 在ios 中因為NSStream類不支援 與一個遠端主機連接配接,而CFStream支援。是以為了使用 NSStream。你須要使用流建立函數CFStreamCreatePairWithSocketToHost或CFStreamCreatePairWithSocketToCFHost來打開一個與遠端主機連接配接的socket并配置設定一對CFStream 對象(CFReadStream和CFWriteStream)。并cast這些對象到NSStream 對象(相應NSInputStream 和 NSOutputStream)。進而能夠使用NSStream類的相關接口進行相關網絡程式設計。如設定接收網絡事件的代理對象,排程到目前的run loop,然後打開它們進行相應處理。

代碼片段例如以下:

       在NSStream對象打開後。當接收到相關的stream-event網絡消息,其代理對象中的handleEvent: 函數被調用,進而進行流相關的網絡消息處理,  如發送相關協定的請求或接收應答等。

下面為handleEvent: 函數進行事件處理的代碼片段:

三、url 程式設計模式

         url 程式設計模式通過URL 的方式來實作網絡程式設計。不論什麼要存取的網絡資源(包含區域網路和廣域網)都能夠用一個URL來表示和存取,并支援裝置間的資源共享。url 程式設計模式系統提供http, https, file, ftp, data等五種協定支援,并同意使用者自己開發和登記相關類來支援另外的應用層網絡協定,進行協定的擴充。

        url 程式設計模式在IOS系統能夠使用兩種程式設計接口:NSURLSession 和NSURLConnection。

        對于iOS 7 以後的最新系統推薦使用NSURLSession API。對于老版本号因為不支援NSURLSession,是以必須使用NSURLConnection API。

NSURLSession程式設計模式是對相關的連接配接請求通過一個會話來完畢,應用通過建立一系列sessions來實作網絡通訊。每個session協調一組相關資料的傳輸任務。在每個session内,應用加入一系列任務。每個任務表現一個特定URL 請求。

        NSURLSession相比NSURLConnection的長處是支援在應用挂起、停止或crashed時能夠在背景繼續下載下傳資料,即支援任務的取消、重新啟動(恢複)、挂起,以及支援從已挂起、取消或失敗的下載下傳中又一次恢複下載下傳的能力。

         對于簡單的請求,還能夠直接通過一個簡單的NSURL對象來送出請求。并使用一個NSData記憶體對象或者一個檔案的方式來引出NSURL指向的内容。而NSURLConnection API僅僅能通過構造一個NSURLRequest對象或其子類來發出URL請求來請求下載下傳或上傳URL資料。 使用一個NSURLRequest請求對象封裝一個URL請求,比如HTTP協定方法。除了能夠封裝一些協定特定的屬性外。還能夠規定随意本地cached資料的使用政策。

         對于NSURLRequest請求對象的應答包含兩部分:描寫叙述内容的中繼資料metadata及内容資料本身。兩種API對于使用NSURLRequest請求接收的中繼資料metadata都由NSURLResponse類來封裝。當中包含MIME類型、内容長度、編碼及提供應答的URL等内容。NSURLResponse協定特定的子類還能提供額外的中繼資料。如NSHTTPURLResponse提供協定頭和WEBserver傳回的狀态碼 等資訊。

         NSURLSession API的使用:

         NSURLSession類支援三種會話類型(預設會話類型、暫時會話、背景會話)以及三種類型的任務(資料任務、下載下傳任務、上傳任務)。

         資料任務使用NSData 對象來發送和接收記憶體資料,不存儲資料到一個檔案,是以不支援背景會話。

         下載下傳任務以一個檔案的形式引出資料。并支援在應用沒有執行時的背景下載下傳。

         上傳任務用來上傳資料(檔案),也能夠支援應用沒有執行時的背景上傳。

          預設會話和背景會話的差别是背景會話使用一個分離的程序處理全部的傳輸資料任務,并帶有一些限制:背景會話必須使用特定應用代理來提供事件送出。并僅支援HTTP和HTTPS 協定,不支援其他定制協定,并僅支援上傳和下載下傳任務,不支援資料任務。

         暫時會話不存儲不論什麼資料到磁盤。全部接收的内容都儲存到與會話關聯的RAM中。當會話無效時。RAM中接收的内容自己主動被清除。

   NSURLSession API的使用步驟:

   1 、建立一個NSURLSessionConfiguration配置對象

NSURLSessionConfiguration配置對象提供廣泛的配置選項。包含: 1)、特定于單個會話的私有資料存儲,包含caches, cookies, credentials, 和protocols; 2)、與一個特定請求或一個會話關聯的Authentication; 3)、與一個主機的最大連接配接數; 4)、與一個資源關聯的逾時; 5)、最小和最大TLS版本号支援; 6)、定制的代理詞典。 7)、cookie政策的控制; 8)、HTTP pipelining行為的控制

2、依據配置建立相應的NSURLSession。

       例如以下代碼片段展示了依據不同的配置對象建立不同類型的NSURLSession會話對象。

       NSURLSession API通過代理來實作異步URL内容存取。代理能夠是系統提供的代理,還能夠是應用提供的特定代理對象。任務對象當從server接收到資料或傳輸完畢時調用這些代理對象的方法。

     在建立會話指定相應的代理對象。

3、為會話加入任務;

使用例如以下方法來加入資料任務到一個會話。

dataTaskWithURL(_:) dataTaskWithURL(_:completionHandler:) dataTaskWithRequest(_:)  dataTaskWithRequest(_:completionHandler:) 

使用例如以下方法來加入下載下傳任務到一個會話。

downloadTaskWithURL(_:) downloadTaskWithURL(_:completionHandler:)  downloadTaskWithRequest(_:)  downloadTaskWithRequest(_:completionHandler:)  downloadTaskWithResumeData(_:)  downloadTaskWithResumeData(_:completionHandler:) 

使用例如以下方法來加入上傳任務到一個會話

uploadTaskWithRequest(_:fromData:) uploadTaskWithRequest(_:fromData:completionHandler:)  uploadTaskWithRequest(_:fromFile:) uploadTaskWithRequest(_:fromFile:completionHandler:) uploadTaskWithStreamedRequest(_:) 

         例如以下是資料任務建立代碼片段:     

       下面是下載下傳任務建立代碼片段:         

4、使用代理方法接收資料及狀态資訊

會話的資料任務在使用應用特定代理接收資料時必須實作例如以下兩個代理方法: URLSession:dataTask:didReceiveData:  一次一片的提供請求的資料給會話任務。 URLSession:task:didCompleteWithError: 訓示請求資料已經全部接收。 會話的下載下傳任務在下載下傳檔案時應該實作例如以下代理方法: URLSession:downloadTask:didFinishDownloadingToURL: 下載下傳内容存儲到一個URL指定的一個暫時檔案。在該方法傳回之前,必須把暫時檔案的内容移到一個永久位置。而暫時檔案被删除。 URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:  為應用提供關于目前下載下傳進度的狀态資訊 URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes: 告訴應用已經從從先前的失敗下載下傳中恢複。 URLSession:task:didCompleteWithError:  告訴應用下載下傳已經失敗。 下載下傳失敗恢複處理: 在應用使用cancelByProducingResumeData: 方法取消下載下傳任務時,能夠使用downloadTaskWithResumeData: 或 downloadTaskWithResumeData:completionHandler:方法又一次建立一個新下載下傳任務并傳送cancelByProducingResumeData:産生的恢複資料進而接着繼續下載下傳。 在傳輸失敗時。假設任務可恢複,則調用URLSession:task:didCompleteWithError: 方法。 在傳送給URLSession:task:didCompleteWithError: 方法的參數NSError中的 userInfo 詞典中包含鍵值為NSURLSessionDownloadTaskResumeData的恢複資料,是以能夠使用downloadTaskWithResumeData: 或 downloadTaskWithResumeData:completionHandler:方法又一次建立一個新下載下傳任務來接着恢複資料繼續下載下傳。 系統代理僅能支援主要的URL資源存取任務,不支援認證和背景下載下傳,而且還必須提供一個completion handler block來把傳回的URL資料送出到應用。例如以下是一個使用系統代理的代碼樣例:         

          會話的上傳任務的任務建立和相關代理方法:

          會話的上傳任務使用HTTP  POST方法來上傳資料。

能夠以一個NSData對象、一個檔案或使用一個流為HTTP POST請求的body提供内容。

          在以NSData對象提供上傳資料時,應用調用uploadTaskWithRequest:fromData: 或uploadTaskWithRequest:fromData:completionHandler: 方法來建立上傳任務。

在以檔案形式提供上傳資料時,應用調用uploadTaskWithRequest:fromFile: 或 uploadTaskWithRequest:fromFile:completionHandler:方法來建立上傳任務 在以流方式提供上傳資料時,應用調用uploadTaskWithStreamedRequest:方法來建立上傳任務。 應用特定代理能夠通過實作URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:方法來獲得上傳進度資訊。