GCDAsyncSocket是一个TCP套接字库建立在中央调度。该项目还包含一个基于RunLoop版本,以及UDP套接字库。
CocoaAsyncSocket项目是一个成熟的开源框架,自2003年以来已经存在。因此它已经受益于各种各样的网络开发人员提交的代码或建议的功能。项目的目标是创建功能强大,但易于使用的套接字库。
GCDAsyncSocket的具体功能包括:
经典delegate-style支持.
以下所有结果调用你的委托方法:连接,接受,完成阅读,编写完成,进展,断开,错误,等。委托方法包括一个套接字参数,允许您区分许多实例。
委托调度。
可配置的dispatch_queue每个委托方法调用。这允许并行插座IO和数据处理,以及简单的线程安全。
排队阻塞读和写,可选的超时。
你告诉它读或写什么,当它结束的时候,它就会给你打电话。
自动套接字接受。
如果你告诉它接受连接,它就会给你打电话本身为每个连接的新实例。当然,你可以立即断开。
自动支持IPv4和IPv6。
SSL / TLS的支持。
建立在最新的技术,如kqueues。
独立的一个类。
你不需要把系统在溪流或套接字。类处理的。
GCDAsyncSocket更强大的特性之一是它的排队结构。这允许您控制套接字你方便的时候,而不是当套接字告诉你它是准备好了。几个例子:
// Start asynchronous connection. // The method below will return immediately, // and the delegate method socket:didConnectToHost:port: will // be invoked when the connection has completed. [asyncSocket connectToHost:host onPort:port error:nil]; // At this moment in time, the socket is not yet connected. // It has just started the asynchronous connection attempt. // But AsyncSocket was designed to make socket programming easier for you. // You are free to start reading/writing if it is convenient for you. // So we are going to start the read request for our message header now. // The read request will automatically be queued. // And after the socket connects, this read request will automatically be dequeued and executed. [asyncSocket readDataToLength:LENGTH_HEADER withTimeout:TIMEOUT_NONE tag:TAG_HEADER];
此外,您可以很方便的调用多个读/写请求。
// Start asynchronous write operation
[asyncSocket writeData:msgHeader withTimeout:TIMEOUT_NONE tag:TAG_HEADER];
// We don't have to wait for that write to complete before starting the next one
[asyncSocket writeData:msgBody withTimeout:TIMEOUT_NONE tag:TAG_BODY];
// Start asynchronous read operation.
// Read and ignore the welcome message.
[asyncSocket readDataToData:msgSeparator withTimeout:TIMEOUT_NONE tag:TAG_WELCOME];
// We don't have to wait for that read to complete before starting the next one.
// Read server capabilities.
[asyncSocket readDataToData:msgSeparator withTimeout:TIMEOUT_NONE tag:TAG_CAPABILITIES];
// Send startTLS confirmation ACK. // Remember this is an asynchronous operation. [asyncSocket writeData:ack withTimeout:TIMEOUT_NONE tag:TAG_ACK]; // We don't have to wait for the write to complete before invoking startTLS. // The socket will automatically queue the operation, and wait for previous reads/writes to complete. // Once that has happened, the upgrade to SSL/TLS will automatically start. [asyncSocket startTLS:tlsSettings]; // Again, we don't have to wait for the security handshakes to complete. // We can immediately queue our next operation if it's convenient for us. // So we can start reading the next request from the client. // This read will occur over a secure connection. [asyncSocket readDataToData:msgSeparator withTimeout:TIMEOUT_NONE tag:TAG_MSG];大多数操作超时是可选的参数。
除了这一点,你可能已经注意到标签参数。一旦读/写操作完成,你通过读/写操作期间的标签会通过委托方法传回给你。它不通过套接字发送或从套接字读取。它旨在帮助简化您的委托方法中的代码。例如,您的委托方法可能看起来像这样:
#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是线程安全的。
委派方法
GCDAsyncSocket是异步的。所以对于大多数的方法,当你启动一个操作在一个套接字(连接,接受、阅读、写作)方法将会立即返回,和行动的结果将通过相应的委托方法返回给你。
socket: didConnectToHost: port:
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
时调用一个套接字进行连接,准备开始读和写。主机参数将一个IP地址,而不是一个DNS名称。
socket: didReadData: withTag:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
socket: didReadPartialDataOfLength: tag:
- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag
socket: shouldTimeoutReadWithTag: elapsed: bytesDone:
- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length
socket: didWriteDataWithTag:
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
socket: didWritePartialDataOfLength: tag:
- (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag
socket: shouldTimeoutWriteWithTag: elapsed: bytesDone:
- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag
elapsed:(NSTimeInterval)elapsed
bytesDone:(NSUInteger)length;
socketDidSecure:
- (void)socketDidSecure:(GCDAsyncSocket *)sock
socket: didAcceptNewSocket:
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
newSocketQueueForConnectionFromAddress: onSocket:
- (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock;
return dispatch_queue_create("MyQueue", NULL);如果你是把多个套接字在同一队列,然后应该小心增量保留每次调用该方法。
dispatch_retain(myExistingQueue); return myExistingQueue;socketDidCloseReadStream:
- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock
socketDidDisconnect: withError:
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error
初始化
GCDAsyncSocket使用标准委托范式,但执行所有代表回调函数在给定的委托调度队列。这允许最大并发性,同时提供简单的线程安全。
必须设置一个委托和委托调度队列之前使用套接字,或者你会得到一个错误。
套接字队列的调度队列GCDAsyncSocket实例内部操作。你可以选择设置在初始化套接字队列。如果你选择不去,或者通过NULL,GCDAsyncSocket将自动创建它自己的套接字队列。如果您选择提供一个套接字队列,套接字队列不能并发队列。
代表队列和队列可以是相同的套接字。
init
- (id)init
- (id)initWithSocketQueue:(dispatch_queue_t)sq
initWithDelegate: delegateQueue:
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq
initWithDelegate: delegateQueue: socketQueue:
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
配置
delegate
- (id)delegate
- (void)setDelegate:(id)delegate
设置套接字的代表。
建议您nilify套接字的委托之前释放套接字。有关更多信息,请参见断开连接的方法。
delegateQueue
- (dispatch_queue_t)delegateQueue
setDelegateQueue:
- (void)setDelegateQueue:(dispatch_queue_t)delegateQueue
getDelegate: delegateQueue:
- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
setDelegate: delegateQueue:
- (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue
setAutoDisconnectOnClosedReadStream:
- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag
;
设置autoDisconnectOnClosedReadStream配置选项。看到上面的讨论autoDisconnectOnClosedReadStream方法。
- (BOOL)isIPv4Enabled
默认情况下,IPv4和IPv6都启用。
- (void)setIPv4Enabled:(BOOL)flag
启用或禁用支持IPv4。
注意:这个属性变化已经连接的套接字或接受不影响当前的套接字的连接。这只会影响未来的连接(当前插座断开连接后)。一旦设置,偏好会影响未来所有GCDAsyncSocket实例连接。
- (BOOL)isIPv6Enabled
;
默认情况下,IPv4和IPv6都启用。
- (void)setIPv6Enabled:(BOOL)flag
注意:这个属性变化已经连接的套接字或接受不影响当前的套接字的连接。这只会影响未来的连接(当前插座断开连接后)。一旦设置,偏好会影响未来所有GCDAsyncSocket实例连接。
- (BOOL)isIPv4PreferredOverIPv6
默认情况下,首选协议IPv4。
- (void)setPreferIPv4OverIPv6:(BOOL)flag
- (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr
- (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr
连接
一旦接受或连接方法之一,GCDAsyncSocket实例锁定在和其他接受/连接方法被称为不能没有首先切断socket。
connectToHost: onPort: error:
- (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port error:(NSError **)errPtr
error
:使用默认的接口,不超时。connectToHost: onPort: withTimeout: error:
- (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
connectToHost: onPort: viaInterface: withTimeout: error:
- (BOOL)connectToHost:(NSString *)host
onPort:(UInt16)port
viaInterface:(NSString *)interface
withTimeout:(NSTimeInterval)timeout
error:(NSError **)errPtr
没有时间使用负的时间间隔。
这个方法将返回没有如果检测到一个错误,并设置错误指针(如果有)。可能的错误将是一个零主机,无效的接口,或套接字已经连接。
如果检测到任何错误,该方法将开始一个后台连接操作,并立即返回是的。委托回调用于通知你当套接字连接,或如果主机是不可到达的。
读
读方法不会阻止(异步)。当阅读完整的套接字:didReadData:withTag:委托方法被调用。
你可以选择任何读操作设置一个超时。(不要超时,使用消极的时间间隔)。如果一个读操作超时,相应的“插座:shouldTimeoutReadWithTag…“委托方法选择允许您扩展超时。在一个超时“socketDidDisconnect:withError:”方法被调用。
标签是为了方便。读操作的标记传递给标记传递回到您的套接字:didReadData:withTag:代表回调。您可以使用它作为一个国家id数组索引,部件号码,指针等。
您可以调用多个连续读取方法。读取将请求排队秩序,将列中移除并连续执行。
readDataWithTimeout: tag:
- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag
readDataWithTimeout: buffer: bufferOffset: tag:
- (void)readDataWithTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
tag:(long)tag;
readDataWithTimeout: buffer: bufferOffset: maxLength: tag:
- (void)readDataWithTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
maxLength:(NSUInteger)length
tag:(long)tag;
如果bufferOffset大于给定的缓冲区的长度,该方法将什么也不做,代表将不会被调用。
如果你通过一个缓冲区,你不能以任何方式改变它而GCDAsyncSocket是使用它。完成后,返回的数据在套接字:didReadData:withTag:将给定缓冲区的一个子集。也就是说,它将引用添加到给定的字节缓冲区。
标签是为了方便。读操作的标记传递给标记传递回到你onSocket:didReadData:withTag:代表回调
readDataToLength: withTimeout: tag:
- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag
readDataToLength: withTimeout: buffer: bufferOffset: tag:
- (void)readDataToLength:(NSUInteger)length
withTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
tag:(long)tag;
如果你通过一个缓冲区,你不能以任何方式改变它而GCDAsyncSocket是使用它。完成后,返回的数据在套接字:didReadData:withTag:将给定缓冲区的一个子集。也就是说,它将引用添加到给定的字节缓冲区。
标签是为了方便。读操作的标记传递给标记传递回到你onSocket:didReadData:withTag:代表回调
readDataToData: withTimeout: tag:
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
如果你通过零或零长度的数据“数据”参数,该方法将什么也不做,代表将不会被调用。
从套接字读取一行,使用行分隔符(例如CRLF HTTP)的“数据”参数。注意这种方法不是字符集的注意,因此如果一个分离器可以自然发生的一部分编码字符,读取会过早结束。
readDataToData: withTimeout: buffer: bufferOffset: tag:
- (void)readDataToData:(NSData *)data
withTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
tag:(long)tag;
readDataToData: withTimeout: maxLength: tag:
- (void)readDataToData:(NSData *)data
withTimeout:(NSTimeInterval)timeout
maxLength:(NSUInteger)length
tag:(long)tag;
如果你通过零或零长度的数据“数据”参数,该方法将什么也不做,代表将不会被调用。如果你通过一个最大长度参数小于长度的数据参数,方法将什么也不做,代表不会叫。
标签是为了方便。读操作的标记传递给标记传递回到你onSocket:didReadData:withTag:代表回调。
从套接字读取一行,使用行分隔符(例如CRLF HTTP)的“数据”参数。注意这种方法不是字符集的注意,因此如果一个分离器可以自然发生的一部分编码字符,读取会过早结束。
readDataToData: withTimeout: buffer: bufferOffset: maxLength: tag:
- (void)readDataToData:(NSData *)data
withTimeout:(NSTimeInterval)timeout
buffer:(NSMutableData *)buffer
bufferOffset:(NSUInteger)offset
maxLength:(NSUInteger)length
tag:(long)tag;
如果最大长度为零,没有长度限制执行。否则如果最大长度字节读没有完成阅读,它是治疗类似于一个超时AsyncSocketReadMaxedOutError——关闭套接字。阅读将成功完成如果最大长度字节读取和给定的数据被发现。
如果你通过一个最大长度参数小于长度的数据参数,方法将什么也不做,代表不会叫。如果bufferOffset大于给定的缓冲区的长度,该方法将什么也不做,代表将不会被调用。
如果你通过一个缓冲区,你不能以任何方式改变它而GCDAsyncSocket是使用它。完成后,返回的数据在套接字:didReadData:withTag:将给定缓冲区的一个子集。也就是说,它将引用添加到给定的字节缓冲区。
标签是为了方便。读操作的标记传递给标记传递回到你onSocket:didReadData:withTag:代表回调。
从套接字读取一行,使用行分隔符(例如CRLF HTTP,见下文)的“数据”参数。注意这种方法不是字符集的注意,因此如果一个分离器可以自然发生的一部分编码字符,读取会过早结束。
写
写方法不会阻止(异步)。当编写完整的套接字:didWriteDataWithTag:委托方法被调用。
你可以选择设置一个超时写操作。(不要超时,使用消极的时间间隔)。如果写操作超时,相应的“插座:shouldTimeoutWriteWithTag…“委托方法选择允许您扩展超时。在一个超时“socketDidDisconnect:withError:”方法被调用。
标签是为了方便。写操作的标记传递给标记传递回到您的套接字:didWriteDataWithTag:委托回调。您可以使用它作为一个国家id数组索引,部件号码,指针等。
您可以调用多个连续写方法。写操作将请求排队秩序,将列中移除,并连续执行
writeData: withTimeout: tag:
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag写数据到套接字,并在完成时调用委托。
如果你通过在零或零长度数据,该方法并没有和代表将不会被调用。
果超时时间值是负的,写操作不会使用超时。如果超时为零,写操作将超时如果所有数据不能立即写入套接字当时写操作列中移除。
isDisconnected
- (BOOL)isDisconnected
connectedHost
- (NSString *)connectedHost
返回的IP地址连接(远程)主机字符串格式。
如果没有连接套接字,返回零。
connectedPort
- (UInt16)connectedPort
localHost
- (NSString *)localHost
返回的IP地址的本地接口用于连接。例如,这可能是类似“192.168.0.4”。
如果没有连接套接字,返回零;
connectedAddress
- (NSData *)connectedAddress
返回的地址(远程)主机连接。这是一个“struct sockaddr”值裹着NSData对象。如果插座IPv4,数据将“结构指向sockaddr_in”类型的。如果插座IPv6,数据将“struct sockaddr_in6”类型的。
如果没有连接套接字,返回零。
localAddress
- (NSData *)localAddress
断开
disconnect
- (void)disconnect
[asyncSocket setDelegate:nil delegateQueue:NULL]; [asyncSocket disconnect]; [asyncSocket release];disconnectAfterReading
- (void)disconnectAfterReading
disconnectAfterWriting
- (void)disconnectAfterWriting
disconnectAfterReadingAndWriting
- (void)disconnectAfterReadingAndWriting
startTLS:
- (void)startTLS:(NSDictionary *)tlsSettings
performBlock:
- (void)performBlock:(dispatch_block_t)block
hostFromAddress:
+ (NSString *)hostFromAddress:(NSData *)address
+ (UInt16)portFromAddress:(NSData *)address
+ (BOOL)getHost:(NSString **)hostPtr port:(UInt16 *)portPtr fromAddress:(NSData *)address
Carriage-Return, Line-Feed. (0x0D0A)
+ (NSData *)CRLFData
A common line separator, for use with the readDataToData:... methods.
CRData
+ (NSData *)CRData
Carriage-Return. (0x0D)
A common line separator, for use with the readDataToData:... methods.
LFData
+ (NSData *)LFData
Line-Feed. (0x0A)
A common line separator, for use with the readDataToData:... methods.
ZeroData
+ (NSData *)ZeroData
Zero Byte. Also known as a Null Byte or Null Character (at the end of a string). (0x00)
A common line separator, for use with the readDataToData:... methods.