iOS Socket編程基礎(chǔ)翻譯系列一

詳情請移步github地址查看具體文檔。https://github.com/huang303513/translateOfAppleDocument

同時也歡迎各位有志之士參與我們的翻譯計劃,github地址:https://github.com/wang820203420/IOS-Developer-library-Chinese/tree/master

---------------------------------以下為翻譯文檔----------------------------------------------------

簡介

重要:這是一個為后面內(nèi)容的準(zhǔn)備性的文檔。準(zhǔn)確的說它會討論一些技術(shù),但不是最終的。蘋果官方提供這個文檔的目的是為了讓你熟悉這個模塊的接口。這里提供的信息可能會改變,這個文檔里提到的接口信息會在最終的文檔里面確定。想要了解這個文檔的更新過程,點擊這里Apple Developer website。進入相關(guān)話題的reference library,并且打開它了解。

這個文檔專門講關(guān)于網(wǎng)絡(luò)模塊的相關(guān)知識。至于在這個文檔里面提到的一些其他話題,我們假設(shè)你已經(jīng)熟悉一些基本的網(wǎng)絡(luò)概念。

重要:大部分開發(fā)人員不需要讀這個文檔,并且大部分網(wǎng)絡(luò)應(yīng)用不會需要這個文檔里面的知識(估計意思是大部分app用http)。在你讀這個文檔之前,你需要提前讀Networking Overview以便你更能理解這個文檔里面的內(nèi)容。

如何使用這個文檔

這個文檔包含如下幾節(jié):

使用套接字(Socket)和套接字stream---描述了如何使用套接字和stream來做底層網(wǎng)絡(luò)編程,從POSIX標(biāo)準(zhǔn)層到Foundation框架層。這個部分解釋了現(xiàn)有的最好解決方法來寫客戶端和服務(wù)端。

域名系統(tǒng)(DNS)解析主機---解釋了域名解析系統(tǒng)如何工作,以及如何避開域名解析系統(tǒng)的陷阱。

傳輸層安全(TLS)的正確實現(xiàn)---描述了如何安全的操作傳輸層從而避免讓你的軟件有嚴(yán)重的安全問題。這個部分包括TCP steam(使用CFStream或者NSStream API)和URL請求(使用NSURLConnection API)。

每個部分都是針對要用到相應(yīng)知識來編碼的開發(fā)者。

先決條件

這個文檔假設(shè)你已經(jīng)度過下面的文檔或者理解文檔里面的相應(yīng)的知識:

Networking Overview-講一個互聯(lián)網(wǎng)軟件工作的基本流程,如何避免一些常見的錯誤。

Networking Concepts-描述了以套接字為基礎(chǔ)的網(wǎng)絡(luò)操作和基本概念。

使用套接字和套接字流(stream)

這部分講如何用套接字和套接字stream編程,從POSIX協(xié)議層到Foundation框架層。

重要:這部分將描述如何全面使用套接字連接,有些應(yīng)用用更高一級的API更好比如NSURLConnection。想了解NSURLConnection,讀Networking Overview.

這個部分講一些在Cocoa或者Core Foundation之外的協(xié)議,而且這些協(xié)議是你必須支持的。

在大多數(shù)網(wǎng)絡(luò)層中,軟件被分為兩類:客戶端和服務(wù)端。在高級網(wǎng)絡(luò)層(high-level API)中,這個區(qū)分更明顯了。大多數(shù)用高級網(wǎng)絡(luò)層的都是客戶端。然而,在低級網(wǎng)絡(luò)層中,這個界限一般很模糊。

套接字和數(shù)據(jù)流(stream)編程一般分為下面的兩類:

. 基于分組的通信(Packet-based communication):程序一般一次操作一個數(shù)據(jù)包,監(jiān)聽到數(shù)據(jù)包并發(fā)送一個數(shù)據(jù)包作為回應(yīng)。而且很有可能每個部分都會處理接收到或者發(fā)送的數(shù)據(jù)。網(wǎng)絡(luò)通訊協(xié)議是一致的。

. 基于流的客戶端(Stream-based clients):程序通過TCP來接收或者發(fā)送連續(xù)的數(shù)據(jù)流。對于這種模式,客戶端和服務(wù)端的界限更明顯。客戶端和服務(wù)端對數(shù)據(jù)的處理很相似,但是他們構(gòu)建通訊信道(communication channel)的方式截然不同。

這個部分分為如下幾個部分:

選擇一個API簇(API Family)---描述如何決定使用哪個API簇。

寫一個基于TCP的客戶端---描述如何構(gòu)建優(yōu)雅地TCP連接到服務(wù)器的服務(wù)。

寫一個基于TCP的服務(wù)端---描述當(dāng)我們寫服務(wù)器的事后,如何監(jiān)聽到來的TCP連接。

工作基于分組的通信的套接字---描述如何在非TCP協(xié)議上工作,比如UDP。

選擇一個API簇(API Family)

對于基于套接字的鏈接,你選擇那個API是根據(jù)你是發(fā)送一個鏈接到其他主機還是接受來自其他主機的鏈接。同時也決定于你是否使用TCP或者其他協(xié)議,下面是你做決定的時候需要考慮的一些因素:

.在OS X中,如果你有需要與非MAC平臺的系統(tǒng)通訊,你可以用POSIX C網(wǎng)絡(luò)編程API,這樣你就可以在不同平臺共用你的網(wǎng)絡(luò)模塊。如果你的程序是基于Core Foundation或者Cocoa (Foundation)的運行時循環(huán)(run loop),你也可以使用Core Foundation的 CFStream API來集成POSIX標(biāo)準(zhǔn)的網(wǎng)絡(luò)模塊。另一方面,如果你用GCD,你可以添加一個套接字作為調(diào)度源(dispatch source).

.在iOS中,POSIX標(biāo)準(zhǔn)沒有被支持,因為這個標(biāo)準(zhǔn)不支持移動蜂窩網(wǎng)絡(luò)(cellular radio)或者指定的VPN。通常情況下,你需要從平常的數(shù)據(jù)處理行數(shù)中分開網(wǎng)絡(luò)模塊并且用更高一級的API重寫網(wǎng)絡(luò)模塊的代碼。

注意:如果你用POSIX標(biāo)準(zhǔn)的網(wǎng)絡(luò)模塊代碼,你需要注意到POSIX標(biāo)準(zhǔn)的網(wǎng)絡(luò)API不是協(xié)議無關(guān)的(protocol-agnostic)(你必須處理IPV4和IPV6的不同)。這是一個IP網(wǎng)絡(luò)層的一個API而一個名字相關(guān)(connect-by-name)API,這意味著你必須做一些額外的工作,如果你想實現(xiàn)一些相同的內(nèi)部鏈接特性和更高一級的API的健壯性問題。在你決定使用POSIX標(biāo)準(zhǔn)的網(wǎng)絡(luò)模塊以前,你需要讀Avoid Resolving DNS Names Before Connecting to a Host

.對于監(jiān)聽一個端口的守護進程、服務(wù)、非TCP的鏈接,使用POSIX標(biāo)準(zhǔn)或者Core Foundation(CFSocket)的網(wǎng)絡(luò)模塊API。

.對于用Objective-C寫的客戶端,用它的Foundation框架的API。Foundation框架定義了針對URL鏈接、套接字流、網(wǎng)絡(luò)服務(wù)和其他網(wǎng)絡(luò)任務(wù)的高級接口。在iOS和OS X中,這個框架同時也是最基礎(chǔ)的、UI無關(guān)的Objective-C框架,提供運行時循環(huán)的各種操作、字符串處理、集合類、文件訪問等等。

. 如果客戶端是C語言寫的。用Core Foundation的網(wǎng)絡(luò)API,這個框架和 CFNetwork框架是兩個基于C語言的框架。他們一起定義了一些Foundation框架用到的結(jié)構(gòu)體和函數(shù)。

注意:在OS X中,CFNetwork框架是Core Services框架的子框架;在iOS中,CFNetwork框架是一個獨立的一級框架。

寫一個基于TCP的客戶端

你編寫友好的網(wǎng)絡(luò)連接接口的方式是取決于你選擇的編程語言、連接的類型(TCP,UDP等等)、是否要和其他平臺分享相同的代碼。

.在Objective-C中用NSStream來建立連接。

如果你要連接到一個主機,新建一個CFHost對象(不是NSHost-他們不能無縫橋接(toll-free bridged)),用CFStreamCreatePairWithSocketToHostCFStreamCreatePairWithSocketToCFHost來開始一個套接字連接到指定主機和端口,并且關(guān)聯(lián)兩個CFStream對象。你也可以用NSStream對象。

你也可以用 CFStreamCreatePairWithSocketToNetService 函數(shù)來連接到一個Bonjour service(好像用于蘋果設(shè)備之間的通訊)。讀Discovering and Advertising Network Services來獲取更多信息。

.用POSIX標(biāo)準(zhǔn)如果需要支持跨平臺。

如果你寫的代碼只用與蘋果平臺,name你要避免使用POSIX標(biāo)準(zhǔn)的代碼,因為他們和高層的協(xié)議比起來,他們更難以操作。然而,如果你寫的網(wǎng)絡(luò)模塊代碼必須在不同平臺分享的話,你可以用POSIX標(biāo)準(zhǔn)的網(wǎng)絡(luò)API從而你能復(fù)用同樣的代碼。

千萬別在主線程使用POSIX協(xié)議網(wǎng)絡(luò)的同步API。如果你要用這種API,你必須在一個單獨的線程里。

注意:POSIX協(xié)議網(wǎng)絡(luò)不支持iOS平臺的蜂窩網(wǎng)絡(luò),因為這個原因,iOS平臺不需要POSIX標(biāo)準(zhǔn)的網(wǎng)絡(luò)API。

下面將講NSStream的用法,除非特別標(biāo)明,CFStream API一般都有一個同樣名字的函數(shù),而且實現(xiàn)也相似。

要了解更多POSIX標(biāo)準(zhǔn)的套接字API,讀UNIX Socket FAQ在http://developerweb.net/.

建立一個鏈接

通常情況下,建立一個TCP鏈接到其他主機用的是數(shù)據(jù)流。Streams自動處理TCP鏈接面臨的挑戰(zhàn)。比如,數(shù)據(jù)流提供了通過主機名(hostname)鏈接的能力,在iOS中,數(shù)據(jù)流會自動喚醒設(shè)備得蜂窩模式或者指定的VPN當(dāng)需要的時候(不像CFSocket 或者 BSD Socket)。相比于底層協(xié)議,Streams更相似Cocoa框架的接口,和Cocoa的文件操作API有很大的相似性。

你獲取或者發(fā)送數(shù)據(jù)流取決于你是否要被鏈接或者主動鏈接到一個主機。

.如果你已經(jīng)知道了一個主機的DNS名字或者IP地址,使用 Core Foundation來讀取或者發(fā)送數(shù)據(jù)流通過 CFStreamCreatePairWithSocketToHost函數(shù)。你可以充分利用CFStream和NSStream的無縫轉(zhuǎn)換。把CFReadStreamRef和CFWriteStreamRef對象轉(zhuǎn)換為NSInputStream和 NSOutputStream對象。

.如果你想通過CFNetServiceBrowser對象來鏈接到一個主機,你可以通過CFStreamCreatePairWithSocketToNetService函數(shù)來接收或者發(fā)送數(shù)據(jù)。讀取Discovering and Advertising Network Services

當(dāng)你得到輸出路和輸入流以后,在沒有用arc的情況下你必須馬上占有他們,把他們引用到一個NSInputStream和NSOutputStream對象,并且設(shè)置他們的代理對象(這個對象需要實現(xiàn)NSStreamDelegate協(xié)議)。通過調(diào)用open方法在當(dāng)前運行時循環(huán)上執(zhí)行他們。

注意:如果你需要同時處理一個以上鏈接,你需要區(qū)分是那個輸入流和輸出流關(guān)聯(lián)。最直接的方式你新建一個鏈接對象同時擁有輸入流和輸出流的引用,并且把這個對象設(shè)置為他們的代理。

事件處理

當(dāng)NSOutputStream對象的代理方法stream:handleEvent:被調(diào)用了,并且設(shè)置streamEvent參數(shù)的值為NSStreamEventHasSpaceAvailable,最后調(diào)用 write:maxLength:來發(fā)送數(shù)據(jù)。write:maxLength:方法要么返回發(fā)送的數(shù)據(jù)的長度,要么返回一個負數(shù)表示失敗。如果這個方法返回的數(shù)據(jù)的長度小于你嘗試發(fā)送的數(shù)據(jù)的長度,你必須把沒有發(fā)送的那部分?jǐn)?shù)據(jù)發(fā)送出去通過調(diào)用NSStreamEventHasSpaceAvailable事件。如果發(fā)生錯誤,你需要調(diào)用 streamError方法來確認(rèn)是哪里發(fā)生了錯誤。

當(dāng)NSInputStream對象的代理方法stream:handleEvent:被調(diào)用了,并且設(shè)置streamEvent參數(shù)的值為NSStreamEventHasBytesAvailable。你可以通過 read:maxLength:方法來讀取接收到得數(shù)據(jù)。這個方法返回接收到得數(shù)據(jù)的長度或者返回一個負數(shù)表示接收失敗。

如果接收到的數(shù)據(jù)的長度小于你需要的長度,你必須持有數(shù)據(jù)并且等待直到你收到所有的數(shù)據(jù)。如果發(fā)生錯誤,你需要調(diào)用 streamError方法來確認(rèn)是哪里發(fā)生了錯誤。

如果鏈接的另一端中斷了鏈接:

你的鏈接代理方法stream:handleEvent:被調(diào)用。并且streamEvent參數(shù)設(shè)置為NSStreamEventHasBytesAvailable。如果你去讀取接收到的數(shù)據(jù),你會發(fā)現(xiàn)長度為零。

你的代理方法stream:handleEvent: 會被調(diào)用。并且streamEvent參數(shù)被設(shè)置為 NSStreamEventEndEncountered。

當(dāng)上面兩個事件的其中一個發(fā)生了,代理方法需要處理鏈接操作結(jié)束工作和清理工作。

結(jié)束鏈接

當(dāng)結(jié)束一個鏈接的時候,我們首先要把它從當(dāng)前運行時循環(huán)移除,設(shè)置鏈接的代理為nil(代理對象并沒有被retain)。通過close方法關(guān)閉與鏈接關(guān)聯(lián)的兩個數(shù)據(jù)流,最后在釋放者兩個數(shù)據(jù)流對象(如果你沒有使用ARC)或者把他們設(shè)置為nil。這就是通常的關(guān)閉鏈接的方式。然而,如果有下面兩種情況你需要手動關(guān)閉鏈接:

對于一個數(shù)據(jù)流,如果你通過 setProperty:forKey: 方法設(shè)置 kCFStreamPropertyShouldCloseNativeSocket屬性值為kCFBooleanFalse。

如果你通過CFStreamCreatePairWithSocket方法創(chuàng)建以BSD套接字為基礎(chǔ)的數(shù)據(jù)流。一般情況下,數(shù)據(jù)流是在一個系統(tǒng)套接字(native socket)的基礎(chǔ)上創(chuàng)建的,并且關(guān)閉的時候不會關(guān)閉底層的套接字。但是,你也可以設(shè)置自動關(guān)閉底層套接字通過設(shè)置kCFStreamPropertyShouldCloseNativeSocket屬性值為kCFBooleanTrue。

更多信息

要了解更多, 讀[Stream Programming Guide]和[Using NSStreams For A TCP Connection Without NSHost]中的[Setting Up Socket Streams]部分, 或者下載SimpleNetworkStreams工程來看看.

下一步將翻譯socket的服務(wù)器部分。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,527評論 19 139
  • CFNetwork Concepts @官方文檔翻譯-李冰 @譯文 CFNetwork給予你能力去全面的控制協(xié)議棧...
    醉臥欄桿聽雨聲閱讀 2,597評論 0 6
  • 一、概念 首先,理清一些概念 TCP/IP和UDP,HTTP協(xié)議,Socket 1.TCP/IP和UDP,是網(wǎng)絡(luò)中...
    _AJH閱讀 4,420評論 0 18
  • 生活在繼續(xù),奔波忙碌晝夜不停。 多想每天能和你一起, 看車水馬龍,聽春風(fēng)耳語, 日出日落,春去冬來,始終有你。 陳...
    Ever_devil閱讀 225評論 0 0
  • Summary How to be brilliant in daily life and job is the ...
    谷音sp閱讀 560評論 0 0

友情鏈接更多精彩內(nèi)容