本人有若干成套學(xué)習(xí)視頻, 可試看! 可試看! 可試看, 重要的事情說三遍 包含Java
, 數(shù)據(jù)結(jié)構(gòu)與算法
, iOS
, 安卓
, python
, flutter
等等, 如有需要, 聯(lián)系微信tsaievan
.
GCDAsynSocket是一個建立在GCD上的TCP socket庫, 這個項目同樣包含基于Runloop的版本, 以及UDP socket庫.
GCDAsynSocket項目是一個成熟的開源框架, 大約成型于2013年. 得益于廣大網(wǎng)絡(luò)開發(fā)者提交代碼或者給出建議. 這個項目的目的是創(chuàng)建一個功能強大, 便于使用的socket庫.
GCDAsynSocket的特點包括:
-
支持經(jīng)典代理模式.
以下所有操作都會調(diào)用代理方法 : 連接, 接收, 讀, 寫, 進(jìn)程, 斷開連接, 錯誤處理等, 代理方法包含一個socket參數(shù), 使得你便于區(qū)別不同的socket實例.
-
代理分發(fā)
每一個代理方法都會在可配置的線程被調(diào)用. 所以, 并發(fā)socket IO, 并發(fā)數(shù)據(jù)處理, 以及線程安全成為可能.
-
讀寫隊列不阻塞, 超時可選
你告訴socket讀什么, 寫什么, 完成之后調(diào)用代理
-
socket自動接收
如果你告訴socket允許連接, 它就會調(diào)用代理告知連接成功, 當(dāng)然, 你也可以立即斷開連接
支持 IPv4和IPv6
支持SSL/TLS
基于GCD和kqueues的最新技術(shù)
-
在類中, 自己包含自己
你不必糾纏于各種流和sockets, 這個類都幫你處理了
GCDAsynSocket的一個強大特征之一就是它的隊列結(jié)構(gòu), 這便于你控制這些socket, 而不必等到socket告訴你已經(jīng)就緒. 例如:
// 開始異步連接
// 下面這個方法很快會return掉
// 連接完成之后, 代理方法socket:didConnectToHost:port: 就會立即被調(diào)用
[asyncSocket connectToHost:host onPort:port error:nil];
// 走到這一行代碼時, socket還沒有連接
// 只是試圖開始異步連接.
// 但是這個框架就是設(shè)計用來讓你便于使用socket的
// 你完全可以在這里就開始往socket里面讀數(shù)據(jù)或者寫數(shù)據(jù)
// 所以我們在這里發(fā)起我們消息頭的讀請求
// 讀請求會自動被加入隊列
// 等到socket連接成功后, 讀請求會自動出列并執(zhí)行
[asyncSocket readDataToLength:LENGTH_HEADER withTimeout:TIMEOUT_NONE tag:TAG_HEADER];
另外, 你可以發(fā)起多個 讀/寫 請求.
// 開始異步的寫操作
[asyncSocket writeData:msgHeader withTimeout:TIMEOUT_NONE tag:TAG_HEADER];
// 我們不必等到上一個寫操作完成, 就可以開始下一個寫操作
[asyncSocket writeData:msgBody withTimeout:TIMEOUT_NONE tag:TAG_BODY];
// 開始異步讀操作.
// 讀且忽略歡迎信息
[asyncSocket readDataToData:msgSeparator withTimeout:TIMEOUT_NONE tag:TAG_WELCOME];
// 我們不必等到上一個讀操作完成, 就可以開始下一個讀操作
// 讀服務(wù)器能力
[asyncSocket readDataToData:msgSeparator withTimeout:TIMEOUT_NONE tag:TAG_CAPABILITIES];
隊列架構(gòu)甚至擴展至可以支持SSL/TLS
// 發(fā)出 startTLS 確認(rèn) ACK.
// 記住, 這是一個異步操作
[asyncSocket writeData:ack withTimeout:TIMEOUT_NONE tag:TAG_ACK];
// 我們不必等到上一個寫操作完成, 就可以開始發(fā)起startTLS
// startTLS請求會自動被加入隊列
// 等到寫操作完成之后, startTLS請求會自動出列并執(zhí)行
// 一旦請求王城, SSL/TLS 就會自動升級并執(zhí)行
[asyncSocket startTLS:tlsSettings];
// 再說一遍, 我們不會等到安全握手完成
// 我們可以立即將下一個操作加入隊列
// 所以我們可以立即讀取客戶端的下一條請求
// 這個讀請求會在安全連接之后發(fā)生
[asyncSocket readDataToData:msgSeparator withTimeout:TIMEOUT_NONE tag:TAG_MSG];
超時對于大多數(shù)操作來說是可選參數(shù)
另外, 你可能注意到了tag參數(shù), 你傳進(jìn)去的tag參數(shù), 在讀寫操作完成之后調(diào)用代理方法的時候再回傳給你, 這個參數(shù)并不會寫到socket里面, 再從socket里面寫出來. 這樣設(shè)計是為了方便你在代理方法中更簡單地編碼, 例如:
#define TAG_WELCOME 10
#define TAG_CAPABILITIES 11
#define TAG_MSG 12
...
- (void)socket:(AsyncSocket *)sender didReadData:(NSData *)data withTag:(long)tag
{
if (tag == TAG_WELCOME)
{
// Ignore welcome message
}
else if (tag == TAG_CAPABILITIES)
{
[self processCapabilities:data];
}
else if (tag == TAG_MSG)
{
[self processMessage:data];
}
}
GCDAsyncSocket是線程安全的
執(zhí)照
這個類是公開的
最初由 Robbie Hanson 于2010年第三季度創(chuàng)建
由 Deusty Designs 和 the Mac 開發(fā)社區(qū)維護
文檔
代理方法
- socket: didConnnectToHost:port:
- socket: didReadData:WithTag:
- socket: didReadPartialDataOfLength:tag:
- socket: shouldTimeoutReadWithTag:elapsed:bytesDone:
- socket: didWriteDataWithTag:
- socket: didWritePartialDataOfLength:tag:
- socket: shouldTimeoutWriteWithTag:elapsed:bytesDone:
- socketDidSecure:
- socket: didAcceptNewSocket:
- newSocketQueueForConnectionFromAddress:onSocket:
- socketDidCloseReadStream:
- socketDidDisconnect:withError:
初始化
- init
- initWithSocketQueue:
- initWithDelegate:delegateQueue:
- initWithDelegate:delegateQueue:socketQueue:
配置
- delegate
- setDelegate:
- delegateQueue
- setDelegateQueue:
- getDelegate:delegateQueue:
- setDelegate:delegateQueue:
- autoDisconnectOnClosedReadStream
- setAutoDisconnectOnClosedReadStream:
- isIPv4Enabled
- setIPv4Enabled:
- isIPv6Enabled
- setIPv6Enabled:
- isIPv4PreferredOverIPv6
- setPreferIPv4OverIPv6:
接受
- acceptOnPort:error:
- acceptOnInterface:port:error:
連接
connectToHost: onPort: error:
connectToHost: onPort: withTimeout: error:
connectToHost: onPort: viaInterface: withTimeout: error:
ReadingreadDataWithTimeout: tag:
readDataWithTimeout: buffer: bufferOffset: tag:
readDataWithTimeout: buffer: bufferOffset: maxLength: tag:
readDataToLength: withTimeout: tag:
readDataToLength: withTimeout: buffer: bufferOffset: tag:
readDataToData: withTimeout: tag:
readDataToData: withTimeout: buffer: bufferOffset: tag:
readDataToData: withTimeout: maxLength: tag:
readDataToData: withTimeout: buffer: bufferOffset: maxLength: tag:
寫
- writeData: withTimeout: tag:
診斷
- isDisconnected
- connectedHost
- connectedPort
- localHost
- localPort
- connectedAddress
- localAddress
- isIPv4
- isIPv6
斷開連接
- disconnect
- disconnectAfterReading
- disconnectAfterWriting
- disconnectAfterReadingAndWriting
安全
- startTLS
高級
- performBlock:
- socketFD
- socket4FD
- socket6FD
- readStream
- writeStream
- sslContext
實用
- hostFromAddress:
- portFromAddress:
- getHost: port: fromAddress:
- CRLFData
- CRData
- LFData
- ZeroData
代理方法
GCDAsyncSocket是異步的, 所以對大多數(shù)方法來說, 當(dāng)你在socket上開始一個操作時(連接, 接受, 讀, 寫), 方法都會立即返回, 操作的結(jié)果將會通過相關(guān)的響應(yīng)代理方法返回給你.
socket: didConnectToHost: port:
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
當(dāng)socket成功連接并準(zhǔn)備開始讀寫的時候調(diào)用, 主機參數(shù)是IP地址, 而不是DNS解析域名
socket: didReadData: withTag:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
當(dāng)socket完成讀取請求數(shù)據(jù)進(jìn)內(nèi)存的時候調(diào)用, 如果發(fā)生錯誤, 則不會調(diào)用
tag參數(shù)是你請求讀操作的時候傳入的, 比如在readDataWithTimeout: tag: 方法中.
socket: didReadPartialDataOfLength: tag:
- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag
當(dāng)socket還在讀數(shù)據(jù), 但是還沒有完成讀操作的時候調(diào)用. 當(dāng)你使用readDataToData:或者 readDataToLength: 等方法時調(diào)用, 這個代理方法可以用在例如更新進(jìn)度條等例子里.
tag參數(shù)是你請求讀操作的時候傳入的, 比如在readDataToLength: WithTimeout: tag: 方法中.
socket: shouldTimeoutReadWithTag: elapsed: bytesDone:
- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length
讀操作超時, 未完成時調(diào)用. 這個方法允許你設(shè)置超時時長. 如果你返回一個正的時間間隔(>0), 讀操作的超時就將按照設(shè)置的來進(jìn)行, 如果你未實現(xiàn)這個代理方法, 或者返回一個非正時間間隔(<=0), 讀操作的超時就跟平常一樣
流逝時間(elapsed)參數(shù)是初始超時, 加上每一次調(diào)用這個方法時超時時間累加之和, 長度(length)參數(shù)表示到目前為止, 讀操作已讀的字節(jié)長度
注意: 如果你在這個代理方法中返回一個正數(shù), 那么在一次讀操作中, 這個方法會被調(diào)用多次
socket: didWriteDataWithTag:
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
當(dāng)socket完成寫入請求的時候調(diào)用, 如果發(fā)生錯誤, 則不會調(diào)用
tag參數(shù)是你請求讀操作的時候傳入的, 比如在writeDataWithTimeout: tag: 方法中.
socket: didWritePartialDataOfLength: tag:
- (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag
當(dāng)socket已經(jīng)寫入一些數(shù)據(jù), 但是還沒有完成整個寫操作時調(diào)用, 這個方法可能用于更新進(jìn)度條之類的例子中
tag參數(shù)是你請求讀操作的時候傳入的, 比如在writeDataWithTimeout: tag: 方法
socket: shouldTimeoutWriteWithTag: elapsed: bytesDone:
- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length;
寫操作超時, 未完成時調(diào)用. 這個方法允許你設(shè)置超時時長. 如果你返回一個正的時間間隔(>0), 寫操作的超時就將按照設(shè)置的來進(jìn)行, 如果你未實現(xiàn)這個代理方法, 或者返回一個非正時間間隔(<=0), 寫操作的超時就跟平常一樣
流逝時間(elapsed)參數(shù)是初始超時, 加上每一次調(diào)用這個方法時超時時間累加之和, 長度(length)參數(shù)表示到目前為止, 寫操作已寫入的字節(jié)長度
注意: 如果你在這個代理方法中返回一個正數(shù), 那么在一次寫操作中, 這個方法會被調(diào)用多次
socketDidSecure:
- (void)socketDidSecure:(GCDAsyncSocket *)sock
當(dāng)socket成功完成SSL/TLS談判的時候調(diào)用, 這個方法, 只有在你使用了startTLS方法之后才會調(diào)用, 否則不會調(diào)用
如果SSL/TLS談判失敗(例如證書無效等原因), socket將會立即關(guān)閉, 且socketDidDisconnect:withError:這個代理方法將會被立即調(diào)用, 錯誤代碼就是SSL錯誤代碼
在蘋果的Security.framework中的SecureTransport.h文件中查閱SSL錯誤碼以及其對應(yīng)的含義
socket: didAcceptNewSocket:
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
當(dāng)一個"服務(wù)器"socket接受一個連過來的"客戶端"socket時, 將會調(diào)用此代理方法. 另一個socket將會產(chǎn)生去處理它.
你必須持有newSocket如果你希望保持連接的話, 否則, 新的socket實例將會被釋放, 產(chǎn)生的連接將會關(guān)閉
默認(rèn)新的socket將會使用同一個代理和代理隊列, 當(dāng)然, 你也可以隨時改變它
默認(rèn)socket將會產(chǎn)生自己內(nèi)部的socket隊列去運行. 這也是可以通過實現(xiàn)newSocketQueueForConnectionFromAddress:onSocket: method這個代理方法來配置
newSocketQueueForConnectionFromAddress: onSocket:
- (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock;
這個方法將會在socket:didAcceptNewSocket:方法之前立即調(diào)用, 這個方法允許監(jiān)聽socket去指定socketQueue(socket隊列)給新的那個已經(jīng)接受的socket, 如果這個方法沒有實現(xiàn), 或者返回NULL, 新的已經(jīng)接受的socket將會創(chuàng)建一個自己的默認(rèn)隊列.
因為你無法自動釋放一個dispatch_queue(派發(fā)隊列), 這個方法使用"new"這個前綴在方法名前去指定這個返回的隊列已經(jīng)被持有了
因而你可以在實現(xiàn)中這樣寫:
return dispatch_queue_create("MyQueue", NULL);
如果你將多個socket放在同一個隊列中, 那么就要注意, 每調(diào)用一次這個方法, 都要增加隊列的引用計數(shù)
例如, 你的代碼應(yīng)該這樣實現(xiàn):
dispatch_retain(myExistingQueue);
return myExistingQueue;
socketDidCloseReadStream:
- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock
如果讀流關(guān)閉將會調(diào)用此方法, 但寫入流依然可寫
這個方法只有在autoDisconnectOnClosedReadStream被設(shè)置為NO的時候才會調(diào)用, 看autoDisconnectOnClosedReadStream的討論以獲取更多信息
socketDidDisconnect: withError:
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error
當(dāng)socket斷開連接時調(diào)用, 不管是正常斷開還是因為出錯斷開
如果你調(diào)用disconnect方法, 且socket還沒有斷開, 那么這個代理方法將會在disconnect方法return之前調(diào)用 (因為disconnect方法是同步的)
初始化
GCDAsyncSocket使用標(biāo)準(zhǔn)的代理范例, 但它在指定的代理分發(fā)隊列中執(zhí)行代理回調(diào). 這使得在同一時間允許最大并發(fā), 且保證線程安全
你必須在試圖使用socket之前設(shè)置代理和代理隊列, 否則將會報錯
socket隊列是一個分發(fā)隊列, 在這個隊列中, GCDAsyncSocket實例在這個隊列中進(jìn)行相應(yīng)的操作. 你可以在初始化時可選地設(shè)置socket隊列. 如果你不選擇, 或者傳入NULL, GCDAsyncSocket將自動創(chuàng)建它自己的隊列, 如果你選擇提供socket隊列, 這個socket隊列必須不是一個并發(fā)隊列.
代理隊列和socket隊列可以是同一個
init
- (id)init
觸發(fā)指定構(gòu)造器, 參數(shù)值為nil. 你需要在使用socket之前設(shè)置代理以及代理隊列
initWithSocketQueue:
- (id)initWithSocketQueue:(dispatch_queue_t)sq
以指定socket隊列, 觸發(fā)指定構(gòu)造器. 你需要在使用socket之前設(shè)置代理以及代理隊列
initWithDelegate: delegateQueue:
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq
以給定的代理和代理隊列觸發(fā)指定構(gòu)造器
initWithDelegate: delegateQueue: socketQueue:
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
指定構(gòu)造器
以指定的代理和代理分發(fā)隊列創(chuàng)建socket
socket分發(fā)隊列是可選的. socket將在這條隊列內(nèi)部進(jìn)行操作. 如果是NULL, 新的分發(fā)隊列將自動被創(chuàng)建. 如果你選擇提供一條socket隊列, socket隊列不能是并發(fā)隊列
代理隊列和socket隊列可以是一樣的
配置
delegate
- (id)delegate
返回當(dāng)前socket設(shè)置的代理對象
setDelegate:
- (void)setDelegate:(id)delegate
推薦你在釋放socket對象之前設(shè)置socket代理. 在disconnect方法中獲取更多信息
delegateQueue
- (dispatch_queue_t)delegateQueue
返回當(dāng)前socket設(shè)置的代理隊列, 所有代理方法將在這個隊列里異步調(diào)用
setDelegateQueue:
- (void)setDelegateQueue:(dispatch_queue_t)delegateQueue
為socket設(shè)置代理隊列. 調(diào)用此方法后, 將來所有代理方法將被分發(fā)到指定隊列
getDelegate: delegateQueue:
- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
代理和代理隊列通常同時出現(xiàn), 這個方法提供了一個線程安全的途徑在一個操作中去獲取當(dāng)前代理配置(包括代理及其隊列)
setDelegate: delegateQueue:
- (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue
提供了一條簡便且線程安全的方法在一個操作中去更改代理和代理隊列
如果你打算更改代理和代理隊列, 推薦使用這個方法
autoDisconnectOnClosedReadStream
- (BOOL)autoDisconnectOnClosedReadStream
一般來講, socket不會關(guān)閉直到會話結(jié)束. 然而, 技術(shù)上可以實現(xiàn)遠(yuǎn)端關(guān)閉socket寫入流. socket將會被通知沒有更多的數(shù)據(jù)將要被讀, 但socket將依然可寫并且遠(yuǎn)端繼續(xù)接收數(shù)據(jù)
這個令人困惑的實用參數(shù)阻止了一個觀點, 那就是客戶端在發(fā)送一個請求給服務(wù)器之后, 將關(guān)閉其寫入流, 然后通知服務(wù)器, 沒有更多的請求了. 實際上, 這一技術(shù)對服務(wù)器開發(fā)者沒什么幫助
更糟糕的是, 從TCP的角度來說, 沒有辦法區(qū)別讀流關(guān)閉和整個socket關(guān)閉, 這都將導(dǎo)致TCP棧收到一個FIN包. 唯一的方法區(qū)別就是依靠繼續(xù)寫入socket. 如果只有讀流被關(guān)閉, 寫將仍然可以進(jìn)行, 否則, 將會發(fā)生錯誤(當(dāng)遠(yuǎn)端發(fā)給我們一個RST包)
另外技術(shù)上的挑戰(zhàn)和困惑是, 很多高級的socket/stream 沒有提供解決此類問題的API. 如果讀流被關(guān)閉, API將通知socket立即關(guān)閉, 同時也關(guān)閉寫入流, 事實上, 蘋果的CFStream就是這么做的. 起初看起來是一個糟糕的設(shè)計, 但事實上它簡化了開發(fā).
大部分情況下, 讀流被關(guān)閉是因為遠(yuǎn)端關(guān)閉了socket. 因而在這個定上關(guān)閉socket就能夠說得通了. 事實上, 這是大多數(shù)網(wǎng)絡(luò)開發(fā)者希望看到的. 然而, 如果你在寫一個服務(wù)器, 這個服務(wù)器跟過多的客戶端交互, 你可能會遇到一個客戶端, 使用這種不被鼓勵的關(guān)閉寫流的技術(shù). 如果是這種情況的話, 你可以設(shè)置屬性為NO, 然后利用 socketDidCloseReadStream 代理方法.
默認(rèn)值為YES
setAutoDisconnectOnClosedReadStream:
- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag
設(shè)置autoDisconnectOnClosedReadStream配置選項, 詳見autoDisconnectOnClosedReadStream方法
isIPv4Enabled
- (BOOL)isIPv4Enabled
默認(rèn)情況下, IPv4和IPv6都可用的
對于接收連接時, 這意味著GCDAsyncSocket自動支持兩種協(xié)議, 并且能夠接收任意一種協(xié)議的鏈接
對于發(fā)送鏈接時, 這意味著GCDAsyncSocket能夠連接運行任意一種協(xié)議的主機, 如果DNS解析返回IPv4結(jié)果, 那么GCDAsyncSocket自動使用IPv4, 如果DNS解析返回IPv6結(jié)果, 那么GCDAsyncSocket自動使用IPv6, 如果DNS解析返回IPv4結(jié)果和IPv6結(jié)果, 那么GCDAsyncSocket會使用優(yōu)先的那一個, 優(yōu)先的是IPv4, 但也可能是根據(jù)要求配置的.
setIPv4Enabled:
- (void)setIPv4Enabled:(BOOL)flag
啟用和禁用IPv4的支持
注意: 如果socket已經(jīng)連接或者接收連接, 更改這個屬性無法影響當(dāng)前socket, 只會改變以后的socket連接(當(dāng)前的socket連接切斷之后). 一旦設(shè)置, 這個偏好將會影響以后所有的基于GCDAsyncSocket實例的socket連接.
isIPv6Enabled
- (BOOL)isIPv6Enabled
默認(rèn)情況下, IPv4和IPv6都可用的
對于接收連接時, 這意味著GCDAsyncSocket自動支持兩種協(xié)議, 并且能夠接收任意一種協(xié)議的鏈接
對于發(fā)送鏈接時, 這意味著GCDAsyncSocket能夠連接運行任意一種協(xié)議的主機, 如果DNS解析返回IPv4結(jié)果, 那么GCDAsyncSocket自動使用IPv4, 如果DNS解析返回IPv6結(jié)果, 那么GCDAsyncSocket自動使用IPv6, 如果DNS解析返回IPv4結(jié)果和IPv6結(jié)果, 那么GCDAsyncSocket會使用優(yōu)先的那一個, 優(yōu)先的是IPv4, 但也可能是根據(jù)要求配置的.
setIPv6Enabled:
- (void)setIPv6Enabled:(BOOL)flag
啟用和禁用IPv6的支持
注意: 如果socket已經(jīng)連接或者接收連接, 更改這個屬性無法影響當(dāng)前socket, 只會改變以后的socket連接(當(dāng)前的socket連接切斷之后). 一旦設(shè)置, 這個偏好將會影響以后所有的基于GCDAsyncSocket實例的socket連接.
isIPv4PreferredOverIPv6
- (BOOL)isIPv4PreferredOverIPv6
默認(rèn)情況下, 優(yōu)先的協(xié)議是IPv4
setPreferIPv4OverIPv6:
- (void)setPreferIPv4OverIPv6:(BOOL)flag
設(shè)置有限的協(xié)議, 詳情請看isIPv4Enabled方法
接收
一旦接收或者連接方法被調(diào)用, GCDAsyncSocket實例將被鎖定, 其他的接收/連接將無法被調(diào)用, 除非socket連接斷開
當(dāng)socket接收一個連接的時候, GCDAsyncSocket調(diào)用以下代理方法(按時間先后順序):
- newSocketQueueForConnectionFromAddress:onSocket:
- socket:didAcceptNewSocket:
你的服務(wù)器代碼必須持有已經(jīng)接收的socket(如果你想接收它的話), 否則, 新接收的socket將會在代理方法返回之后被銷毀(此時socketDidDisconnect:withError:將會被調(diào)用)
acceptOnPort: error:
- (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr
告訴socket在指定端口監(jiān)聽和接收連接. 當(dāng)一個連接被接收, 新的GCDAsyncSocket實例對象將被產(chǎn)生去處理這個連接, socket:didAcceptNewSocket: 這個代理方法將會被調(diào)用
這個socket將會在所有可得的接口監(jiān)聽(例如: wifi, 以太網(wǎng)等)
如果socket能夠開始監(jiān)聽, 那么這個方法返回YES, 如果發(fā)生錯誤, 這個方法返回NO, 并且設(shè)置可選的errPtr參數(shù). 例如, 代理沒有設(shè)置, 或者已經(jīng)接收連接, 都會導(dǎo)致這個發(fā)生錯誤
acceptOnInterface: port: error:
- (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr
這個方法和acceptOnPort: error:差不多, 只是添加了可選參數(shù)去指定接口去監(jiān)聽
例如, 你可以指定socket只接收基于以太網(wǎng)的連接, 而不是其他連接, 例如wifi之上的
這個接口你可以通過名稱來指定(例如 "en1" 或者 "lo0"), 或者通過IP地址來指定(例如 "192.168.4.34"). 你也可以通過特殊的字符串 "localhost" 或者 "loopback" 來指定socket值連接本地機器的socket
你可以通過命令行工具"ifconfig"查看這些接口列表, 或者通過編程, 利用 getifaddrs()這個函數(shù)來獲取
如果要接收任何接口的連接, interface參數(shù)就傳nil. 或者就簡單地使用acceptOnPort: error:這個方法
如果socket能夠開始監(jiān)聽, 那么這個方法返回YES, 如果發(fā)生錯誤, 這個方法返回NO, 并且設(shè)置可選的errPtr參數(shù). 例如, 代理沒有設(shè)置, 或者已經(jīng)接收連接, 或者請求的接口找不到, 都會導(dǎo)致這個發(fā)生錯誤
連接
一旦接收或者連接方法被調(diào)用, GCDAsyncSocket實例將被鎖定, 其他的接收/連接將無法被調(diào)用, 除非socket連接斷開
connectToHost: onPort: error:
- (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port error:(NSError **)errPtr
連接到指定主機和端口
這個方法將會調(diào)用connectToHost:onPort:viaInterface:withTimeout:error: 這個方法, 使用默認(rèn)網(wǎng)絡(luò)接口, 沒有超時時長
返回YES表示異步的連接請求開始. 返回NO表示檢測到發(fā)生錯誤并且會給errPtr參數(shù)賦值
connectToHost: onPort: withTimeout: error:
- (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
連接到指定主機和端口, 超時時長可選
這個方法將會調(diào)用connectToHost:onPort:viaInterface:withTimeout:error: 這個方法, 使用默認(rèn)網(wǎng)絡(luò)接口
connectToHost: onPort: viaInterface: withTimeout: error:
- (BOOL)connectToHost:(NSString *)host
onPort:(UInt16)port
viaInterface:(NSString *)interface
withTimeout:(NSTimeInterval)timeout
error:(NSError **)errPtr
連接到指定主機和端口, 通過可選的網(wǎng)絡(luò)接口, 以及可選的超時時長
主機名可以是域名(例如: "deusty.com") 或者 IP地址字符串 (例如 "192.168.0.2"). 網(wǎng)絡(luò)接口可以是名字 (例如 "en1" 或者 "lo0")或者相應(yīng)的IP地址 (例如 "192.168.4.35")
沒有超時時長請傳入負(fù)值
這個方法將會返回NO, 如果檢測到錯誤的話,并且會給錯誤參數(shù)賦值(如果指定的話). 可能的錯誤是,一個空的主機, 無效的網(wǎng)絡(luò)接口, 或者socket已經(jīng)連接
如果沒有檢測到錯誤, 這個方法將會啟動后臺連接操作并立刻返回YES, 代理回調(diào)將被用來通知你socket連接成功, 或者找不到主機
由于這個類支持隊列讀和寫, 你可以理科開始讀或者寫操作, 所有的讀/寫操作都將被加入隊列, 在socket連接成功之后, 這些讀寫操作將會出列并且按順序執(zhí)行