【IOS网络编程】socket编程 - Asyncsocket
- Phone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作
- 主要特性有:
- 队列的非阻塞的读和写,而且可选超时。你可以调用它读取和写入,它会当完成后告知你
- 自动的socket接收。如果你调用它接收连接,它将为每个连接启动新的实例,当然,也可以立即关闭这些连接
- 委托(delegate)支持。错误、连接、接收、完整的读取、完整的写入、进度以及断开连接,都可以通过委托模式调用
- 基于run loop的,而不是线程的。虽然可以在主线程或者工作线程中使用它,但你不需要这样做。它异步的调用委托方法,使用NSRunLoop。委托方法包括socket的参数,可让你在多个实例中区分
- 自包含在一个类中。你无需操作流或者socket,这个类帮你做了全部
- 支持基于IPV4和IPV6的TCP流
- 加入:AsynSocket.h .m与AsynUdpSocket.h .m四个文件 及CFNetwork.framework
- TCP客户端
- #import "AsyncSocket.h"
- @interface HelloiPhoneViewController : UIViewController {
- UITextField * textField;
- AsyncSocket * asyncSocket;
- }
- @property (retain, nonatomic) IBOutlet UITextField *textField;
- - (IBAction) buttonPressed: (id)sender;
- - (IBAction) textFieldDoneEditing: (id)sender;
- @end
- 在需要联接地方使用connectToHost联接服务器
- 其中initWithDelegate的参数中self是必须。这个对象指针中的各个Socket响应的函数将被ASyncSocket所调用.initWithDelegate把将当前对象传递进去,这样只要在当前对象方法实现相应方法
- asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
- NSError *err = nil;
- if(![asyncSocket connectToHost:host on:port error:&err])
- {
- NSLog(@"Error: %@", err);
- }
- 关于NSData对象
- 无论SOCKET收发都采用NSData对象.它的定义是 http://developer.apple.com/library/mac /#documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/Reference/Reference.html
- NSData主要是带一个(id)data指向的数据空间和长度 length.
- NSString 转换成NSData 对象
- NSData* xmlData = [@"testdata" dataUsingEncoding:NSUTF8StringEncoding];
- NSData 转换成NSString对象
- NSData * data;
- NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- 发送数据
- AsyncSocket writeData 方法来发送数据,它有如下定义
- - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 以下是一个实例语句.
- NSData* aData= [@"test data" dataUsingEncoding: NSUTF8StringEncoding];
- [sock writeData:aData withTimeout:-1 tag:1];
- 在onSocket重载函数,有如定义采用是专门用来处理SOCKET的发送数据的:
- -(void)onSocket(AsyncSocket *)sock didWriteDataWithTag:(long)tag
- {
- NSLog(@"thread(%),onSocket:%p didWriteDataWithTag:%d",[[NSThread currentThread] name],
- sock,tag);
- }
- 接收Socket数据.
- 在onSocket重载函数,有如定义采用是专门用来处理SOCKET的接收数据的.
- -(void) onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
- 在中间将其转换成NSString进行显示.
- NSString* aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- NSLog(@"===%@",aStr);
- [aStr release];
- 6、TCP连接读取制定长度的数据
- socket连接,可能会读取固定长度的字节
- [socket readDataToLength: withTimeout :tag]
- 各方法的解析
- -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- -(void)onSocketDidDisconnect:(ASyncSocket *)sock;
- 当socket由于或没有错误而断开连接,如果你想要在断开连接后release socket,在此方法工作,而在onSocket:willDisconnectWithError 释放则不安全
- -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- -(BOOL)onSocketWillConnect:(AsyncSocket *)sock;
- -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port;
- 当socket连接正准备读和写的时候调用,host属性是一个IP地址,而不是一个DNS 名称
- -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag;
- 当socket已完成所要求的数据读入内存时调用,如果有错误则不调用
- -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag;
- 当一个socket读取数据,但尚未完成读操作的时候调用,如果使用 readToData: or readToLength: 方法 会发生,可以被用来更新进度条等东西
- -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
- 当一个socket已完成请求数据的写入时候调用
- -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- 当一个socket写入一些数据,但还没有完成整个写入时调用,它可以用来更新进度条等东西
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length
- 使用读操作已超时但还没完成时调用,此方法允许随意延迟超时,如果返回一个正的时间间隔,读取的超时将有一定量的扩展,如果不实现这个方法,或会像往常一样返回一个负的时间间隔,elapsed参数是 原超时的总和,加上先前通过这种方法添加的任何补充, length参数是 读操作到目前为止已读取的字节数, 注意,如果返回正数的话,这个方法可能被一个单独的读取多次调用
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length;
- 如果一个写操作已达到其超时但还没完成时调用,同上
- -(void)onSocketDidSecure:(AsyncSocket *)sock;
- 在socket成功完成ssl/tls协商时调用,此方法除非你使用提供startTLS方法时候才调用,
- 如果ssl/tls是无效的证书,socket将会立即关闭,onSocket:willDisconnectWithError:代理方法竟会与特定的ssl错误代码一起调用
- -(BOOL)canSafelySetDelegate
- 用来查看在改变它之前,是否带有与当前的委托有悬而未决的业务(读/写)。当然,应在安全连接或接受委托之前改变委托
- 一旦接收或连接方法之一被调用,AsyncSocket实例会被锁定,其他接收/连接方法在没有先断开socket不会被调用
- 如果尝试失败或超时,这些方法要么返回NO 要么调用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect
- 当传入的连接被接受,AsyncSocket调用多个委托方法。这些方法按照时间顺序排列:
- 1.onSocket:didAcceptNewSocket:
- 2.onSocket:wantsRunLoopForNewSocket:
- 3. onSocketWillConnect:
- 你的服务器的代码将需要保留公认的socket(如果要接受它),最好的地方是要做到这一点可能在onSocket:didAcceptNewSocket:方法
- 在读和写流已经为新接受的socket设置,onSocket:didConnectToHost:port 方法将在适当的运行循环调用
- 多线程注意,如果要想通过实施onSocket:wantsRunLoopForNewSocket:,移动另一个新接受的socket去到另一个循环的socket。然后,应该在调用读和写或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否则读和写时间原定于不正确的runloop,混乱可能会随之而来
- -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr;
- 告诉socket开始听取和接受制定端口上的连接,当一个连接到来的时候,AsyncSocket实例将调用各种委托方法,socket将听取所有可用的接口(wifi,以太网等)
- -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr;
- 连接给定的主机和端口,主机hostname可以是域名或者是Ip地址
- -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr;
- 连接到一个给定的地址,制定一个sockaddr结构包裹住一个NSData对象,例如,NSData对象从NSNetService的地址方法返回,如果有一个现有的sockaddr结构,可以将它转换到一个NSData对象,像这样:
- struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
- struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
- -(void)disconnect;
- 立即断开,任何未处理的读或写都将被丢弃
- 如果socket还没有断开,在这个方法返回之前,onSocketDidDisconnect 委托方法将会被立即调用
- 注意推荐释放AsyncSocket实例的方式:
- [asyncSocket setDelegate:nil];
- [asyncSocket disconnect];
- [asyncSocket release];
- -(void)disconnectAfterReading;
- 在已经完成了所有悬而未决的读取时 断开,在调用之后,读取和写入方法将无用,socket将断开 即使仍有待写入
- - (NSString *)connectedHost;
- - (UInt16)connectedPort;
- - (NSString *)localHost;
- - (UInt16)localPort;
- 返回本地和远程主机和端口给连接的socket,如果没有连接会返回nil或0,主机将会是一个IP地址
- -(NSData *)connectedAddress
- -(NSData *)localAddresss
- 返回本地和远程的地址给连接的socket,指定一个socketaddr结构包裹在一个NSData对象
- readData和writeData方法不会是block(它们是异步的)
- 当读完成 onSocket:didReadData:withTag: 委托方法时调用
- 当写完成 onSocket:didWriteDataWithTag: 委托方法时调用
- 可以选择任何读/写操作的超时设置(为了不超时,使用负时间间隔。)
- 如果读/写操作超时,相应的 onSocket:shouldTimeout...委托方法被调用去选择性地允许我们去延长超时
- 超时后,onSocket:willDisconnectWithError: 方法被调用,紧接着是 onSocketDidDisconnect
- tag是为了方便,可以使用它作为数组的索引、步数、state id 、指针等
- -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag;
- 读取socket上第一次成为可用的字节,如果timeout值是负数的,读操作将不使用timeout
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag;
- 读取socket上第一次成为可用的字节
- 字节将被追加到给定的字节缓冲区,从给定的偏移量开始
- 如果需要,给定的缓冲区大小将会自动增加
- 如果timeout值是负数的,读操作将不使用timeout
- 如果缓冲区为空,socket会为我们创建一个缓冲区
- 如果bufferOffset是大于给定的缓冲区的长度,该方法将无用,委托将不会被调用
- 如果你传递一个缓冲区,当AsyncSocket在使用它的时候你不能以任何方式改变它
- 完成之后,onSocket:didReadData:withTag 返回的数据将是一个给定的缓冲区的子集
- 也就是说,它将会被引用到被追加的给定的缓冲区的字节
- -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取给定的字节数,如果length为0,方法将无用,委托将不会被调用
- -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取给定的字节数,在给定的偏移开始,字节将被追加到给定的字节缓冲区
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的"data"参数
- 如果传递0或者0长度的数据,"data"参数,该方法将无用,委托将不会被调用
- 从socket读取一行,使用"data"参数作为行的分隔符 (如HTTP的CRLF)
- 注意,此方法不是字符集,因此,如果一个分隔符出现,它自然可以作为进行编码的一部分,读取将提前结束
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的“data”参数,在给定的偏移量开始,字节将被追加到给定的字节缓冲区。
- 从socket读取一行,使用"data"参数作为行的分隔符(如HTTP的CRLF)
- -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag;
- 将data写入socket,当完成的时候委托被调用
- - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- 返回当前读或写的进度,从0.0 到 1.0 或者 如果没有读/写的时候返回Nan(使用isNan来检查)
- tag、done、total如果不为空的话,它们将会被填补
- - (void)startTLS:(NSDictionary *)tlsSettings;
- 确保使用ssl/tls连接
- 这方法可被随时调用,tls握手将会发生在所有悬而未决的读/写完成之后。这紧跟着一个发送依赖 StartTLS消息的协议选项,在排队升级到TLS的同一时间,而不必等待写入完成。在这个方法被调用后,任何读写计划 将会发生在安全链接
- 对于可能的keys和TLS设置的值是有据可查的
- 一些可能的keys是:
- * - kCFStreamSSLLevel
- * - kCFStreamSSLAllowsExpiredCertificates
- * - kCFStreamSSLAllowsExpiredRoots
- * - kCFStreamSSLAllowsAnyRoot
- * - kCFStreamSSLValidatesCertificateChain
- * - kCFStreamSSLPeerName
- * - kCFStreamSSLCertificates
- * - kCFStreamSSLIsServer
- 如果你传递空或者空字典,将使用默认的字典
- 默认设置将检查以确保由签署可信的第三方证书机构和没有过期的远程连接的证书
- 然而,它不会验证证书上的名字,除非你给它一个名字,通过kCFStreamSSLPeerName键去验证
- 这对安全的影响是重要的理解
- 想象一下你正试图创建一个到MySecureServer.com的安全连接,但因为一个被攻击的DNS服务器,所以你的socket被定向到MaliciousServer.com
- 如果你只是使用默认设置,MaliciousServer.com 有一个有效的证书
- 默认设置将无法监测到任何问题,因为证书是有效的
- 在这个特殊的情况下,要妥善保护你的连接,应设置kCFStreamSSLPeerName性质为MySecureServer.com.
- 如果事前你不知道对等的名字的远程主机(例如,你不确认它是domain.com" or "www.domain.com"),那么你可以使用默认设置来验证证书,然后在获得验证的发行后使用X509Certificate类来验证,X509Certificate类的CocoaAsyncSocket开源项目的一部分
- -(void)enablePrebuffering
- 对于处理readDataToData请求,数据是必须从socket以小增量的方式读取出来的
- 性能通过允许AsyncSocket去一次性读大块的数据和存储任何一个小的内部缓冲区溢出的东西来大大提高
- 这被称为预缓冲,就好像一些数据在你要求它之前就可能被读取出来
- 如果你经常使用readDataToData,使用预缓冲会有更好的性能,尤其是在iphone上
- 默认的预缓冲状态是由DEFAULT_PREBUFFERING 定义控制的,强烈建议设置其为yes
- 这方法存在一些预缓冲需要一些不可预见的原因被默认禁用的情况,这时,这种方法存在允许当就绪时,可轻松启用预缓冲
- -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
- 当你创建一个AsyncSocket,它被添加到当前线程runloop
- 对于手动创建的socket,在线程上你打算使用它,它是最容易简单的创建的线程上的socket
- 当一个新的socket被接受,委托方法 onSocket:wantsRunLoopForNewSocket 会被调用 允许你在一个单独的线程上放置socket,这个工作最好结合在同一个线程池设计
- 如果,但是,在一个单独的线程上,在之后的时间,你需要移动一个socket,这个方法可以用来完成任务
- 此方法必须从 当前运行的 线程/runloop 的socket 调用
- 注意:此方法调用后,所有进一步的方法应该从给定的runloop上调用这个对象
- 此外,所有委托调用将会发送到给定的runloop
- - (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- - (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- - (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
- 允许你配置 socket 使用的 运行循环模式
- 运行循环模式设置默认是NSRunLoopCommonModes
- 如果你想你的socket 在其他模式下继续操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes
- 可接受的socket将自动 继承相同的运行循环模式就像侦听socket
- 注意:NSRunLoopCommonModes 定义在10.5,对于之前的版本可使用 kCFRunLoopCommonModes
- -(NSArray *)runLoopModes
- 返回当前正在运行的循环模式的AsyncSocket实例, run loop modes的默认设置是NSDefaultRunLoopMode
- -(NSData *)unreadData;
- 一个错误的事件,在 onSocket:willDisconnectWithError: 将会被调用 去读取留在socket上的任何数据
- + (NSData *)CRLFData; // 0x0D0A
- 各方法的解析
- -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- -(void)onSocketDidDisconnect:(ASyncSocket *)sock;
- 当socket由于或没有错误而断开连接,如果你想要在断开连接后release socket,在此方法工作,而在onSocket:willDisconnectWithError 释放则不安全
- -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- -(BOOL)onSocketWillConnect:(AsyncSocket *)sock;
- -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port;
- 当socket连接正准备读和写的时候调用,host属性是一个IP地址,而不是一个DNS 名称
- -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag;
- 当socket已完成所要求的数据读入内存时调用,如果有错误则不调用
- -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag;
- 当一个socket读取数据,但尚未完成读操作的时候调用,如果使用 readToData: or readToLength: 方法 会发生,可以被用来更新进度条等东西
- -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
- 当一个socket已完成请求数据的写入时候调用
- -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- 当一个socket写入一些数据,但还没有完成整个写入时调用,它可以用来更新进度条等东西
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length
- 使用读操作已超时但还没完成时调用,此方法允许随意延迟超时,如果返回一个正的时间间隔,读取的超时将有一定量的扩展,如果不实现这个方法,或会像往常一样返回一个负的时间间隔,elapsed参数是 原超时的总和,加上先前通过这种方法添加的任何补充, length参数是 读操作到目前为止已读取的字节数, 注意,如果返回正数的话,这个方法可能被一个单独的读取多次调用
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length;
- 如果一个写操作已达到其超时但还没完成时调用,同上
- -(void)onSocketDidSecure:(AsyncSocket *)sock;
- 在socket成功完成ssl/tls协商时调用,此方法除非你使用提供startTLS方法时候才调用,
- 如果ssl/tls是无效的证书,socket将会立即关闭,onSocket:willDisconnectWithError:代理方法竟会与特定的ssl错误代码一起调用
- -(BOOL)canSafelySetDelegate
- 用来查看在改变它之前,是否带有与当前的委托有悬而未决的业务(读/写)。当然,应在安全连接或接受委托之前改变委托
- 一旦接收或连接方法之一被调用,AsyncSocket实例会被锁定,其他接收/连接方法在没有先断开socket不会被调用
- 如果尝试失败或超时,这些方法要么返回NO 要么调用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect
- 当传入的连接被接受,AsyncSocket调用多个委托方法。这些方法按照时间顺序排列:
- 1.onSocket:didAcceptNewSocket:
- 2.onSocket:wantsRunLoopForNewSocket:
- 3. onSocketWillConnect:
- 你的服务器的代码将需要保留公认的socket(如果要接受它),最好的地方是要做到这一点可能在onSocket:didAcceptNewSocket:方法
- 在读和写流已经为新接受的socket设置,onSocket:didConnectToHost:port 方法将在适当的运行循环调用
- 多线程注意,如果要想通过实施onSocket:wantsRunLoopForNewSocket:,移动另一个新接受的socket去到另一个循环的socket。然后,应该在调用读和写或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否则读和写时间原定于不正确的runloop,混乱可能会随之而来
- -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr;
- 告诉socket开始听取和接受制定端口上的连接,当一个连接到来的时候,AsyncSocket实例将调用各种委托方法,socket将听取所有可用的接口(wifi,以太网等)
- -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr;
- 连接给定的主机和端口,主机hostname可以是域名或者是Ip地址
- -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr;
- 连接到一个给定的地址,制定一个sockaddr结构包裹住一个NSData对象,例如,NSData对象从NSNetService的地址方法返回,如果有一个现有的sockaddr结构,可以将它转换到一个NSData对象,像这样:
- struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
- struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
- -(void)disconnect;
- 立即断开,任何未处理的读或写都将被丢弃
- 如果socket还没有断开,在这个方法返回之前,onSocketDidDisconnect 委托方法将会被立即调用
- 注意推荐释放AsyncSocket实例的方式:
- [asyncSocket setDelegate:nil];
- [asyncSocket disconnect];
- [asyncSocket release];
- -(void)disconnectAfterReading;
- 在已经完成了所有悬而未决的读取时 断开,在调用之后,读取和写入方法将无用,socket将断开 即使仍有待写入
- - (NSString *)connectedHost;
- - (UInt16)connectedPort;
- - (NSString *)localHost;
- - (UInt16)localPort;
- 返回本地和远程主机和端口给连接的socket,如果没有连接会返回nil或0,主机将会是一个IP地址
- -(NSData *)connectedAddress
- -(NSData *)localAddresss
- 返回本地和远程的地址给连接的socket,指定一个socketaddr结构包裹在一个NSData对象
- readData和writeData方法不会是block(它们是异步的)
- 当读完成 onSocket:didReadData:withTag: 委托方法时调用
- 当写完成 onSocket:didWriteDataWithTag: 委托方法时调用
- 可以选择任何读/写操作的超时设置(为了不超时,使用负时间间隔。)
- 如果读/写操作超时,相应的 onSocket:shouldTimeout...委托方法被调用去选择性地允许我们去延长超时
- 超时后,onSocket:willDisconnectWithError: 方法被调用,紧接着是 onSocketDidDisconnect
- tag是为了方便,可以使用它作为数组的索引、步数、state id 、指针等
- -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag;
- 读取socket上第一次成为可用的字节,如果timeout值是负数的,读操作将不使用timeout
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag;
- 读取socket上第一次成为可用的字节
- 字节将被追加到给定的字节缓冲区,从给定的偏移量开始
- 如果需要,给定的缓冲区大小将会自动增加
- 如果timeout值是负数的,读操作将不使用timeout
- 如果缓冲区为空,socket会为我们创建一个缓冲区
- 如果bufferOffset是大于给定的缓冲区的长度,该方法将无用,委托将不会被调用
- 如果你传递一个缓冲区,当AsyncSocket在使用它的时候你不能以任何方式改变它
- 完成之后,onSocket:didReadData:withTag 返回的数据将是一个给定的缓冲区的子集
- 也就是说,它将会被引用到被追加的给定的缓冲区的字节
- -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取给定的字节数,如果length为0,方法将无用,委托将不会被调用
- -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取给定的字节数,在给定的偏移开始,字节将被追加到给定的字节缓冲区
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的"data"参数
- 如果传递0或者0长度的数据,"data"参数,该方法将无用,委托将不会被调用
- 从socket读取一行,使用"data"参数作为行的分隔符 (如HTTP的CRLF)
- 注意,此方法不是字符集,因此,如果一个分隔符出现,它自然可以作为进行编码的一部分,读取将提前结束
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的“data”参数,在给定的偏移量开始,字节将被追加到给定的字节缓冲区。
- 从socket读取一行,使用"data"参数作为行的分隔符(如HTTP的CRLF)
- -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag;
- 将data写入socket,当完成的时候委托被调用
- - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- 返回当前读或写的进度,从0.0 到 1.0 或者 如果没有读/写的时候返回Nan(使用isNan来检查)
- tag、done、total如果不为空的话,它们将会被填补
- - (void)startTLS:(NSDictionary *)tlsSettings;
- 确保使用ssl/tls连接
- 这方法可被随时调用,tls握手将会发生在所有悬而未决的读/写完成之后。这紧跟着一个发送依赖 StartTLS消息的协议选项,在排队升级到TLS的同一时间,而不必等待写入完成。在这个方法被调用后,任何读写计划 将会发生在安全链接
- 对于可能的keys和TLS设置的值是有据可查的
- 一些可能的keys是:
- * - kCFStreamSSLLevel
- * - kCFStreamSSLAllowsExpiredCertificates
- * - kCFStreamSSLAllowsExpiredRoots
- * - kCFStreamSSLAllowsAnyRoot
- * - kCFStreamSSLValidatesCertificateChain
- * - kCFStreamSSLPeerName
- * - kCFStreamSSLCertificates
- * - kCFStreamSSLIsServer
- 如果你传递空或者空字典,将使用默认的字典
- 默认设置将检查以确保由签署可信的第三方证书机构和没有过期的远程连接的证书
- 然而,它不会验证证书上的名字,除非你给它一个名字,通过kCFStreamSSLPeerName键去验证
- 这对安全的影响是重要的理解
- 想象一下你正试图创建一个到MySecureServer.com的安全连接,但因为一个被攻击的DNS服务器,所以你的socket被定向到MaliciousServer.com
- 如果你只是使用默认设置,MaliciousServer.com 有一个有效的证书
- 默认设置将无法监测到任何问题,因为证书是有效的
- 在这个特殊的情况下,要妥善保护你的连接,应设置kCFStreamSSLPeerName性质为MySecureServer.com.
- 如果事前你不知道对等的名字的远程主机(例如,你不确认它是domain.com" or "www.domain.com"),那么你可以使用默认设置来验证证书,然后在获得验证的发行后使用X509Certificate类来验证,X509Certificate类的CocoaAsyncSocket开源项目的一部分
- -(void)enablePrebuffering
- 对于处理readDataToData请求,数据是必须从socket以小增量的方式读取出来的
- 性能通过允许AsyncSocket去一次性读大块的数据和存储任何一个小的内部缓冲区溢出的东西来大大提高
- 这被称为预缓冲,就好像一些数据在你要求它之前就可能被读取出来
- 如果你经常使用readDataToData,使用预缓冲会有更好的性能,尤其是在iphone上
- 默认的预缓冲状态是由DEFAULT_PREBUFFERING 定义控制的,强烈建议设置其为yes
- 这方法存在一些预缓冲需要一些不可预见的原因被默认禁用的情况,这时,这种方法存在允许当就绪时,可轻松启用预缓冲
- -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
- 当你创建一个AsyncSocket,它被添加到当前线程runloop
- 对于手动创建的socket,在线程上你打算使用它,它是最容易简单的创建的线程上的socket
- 当一个新的socket被接受,委托方法 onSocket:wantsRunLoopForNewSocket 会被调用 允许你在一个单独的线程上放置socket,这个工作最好结合在同一个线程池设计
- 如果,但是,在一个单独的线程上,在之后的时间,你需要移动一个socket,这个方法可以用来完成任务
- 此方法必须从 当前运行的 线程/runloop 的socket 调用
- 注意:此方法调用后,所有进一步的方法应该从给定的runloop上调用这个对象
- 此外,所有委托调用将会发送到给定的runloop
- - (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- - (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- - (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
- 允许你配置 socket 使用的 运行循环模式
- 运行循环模式设置默认是NSRunLoopCommonModes
- 如果你想你的socket 在其他模式下继续操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes
- 可接受的socket将自动 继承相同的运行循环模式就像侦听socket
- 注意:NSRunLoopCommonModes 定义在10.5,对于之前的版本可使用 kCFRunLoopCommonModes
- -(NSArray *)runLoopModes
- 返回当前正在运行的循环模式的AsyncSocket实例, run loop modes的默认设置是NSDefaultRunLoopMode
- -(NSData *)unreadData;
- 一个错误的事件,在 onSocket:willDisconnectWithError: 将会被调用 去读取留在socket上的任何数据
- + (NSData *)CRLFData; // 0x0D0A
- 各方法的解析
- -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- -(void)onSocketDidDisconnect:(ASyncSocket *)sock;
- 当socket由于或没有错误而断开连接,如果你想要在断开连接后release socket,在此方法工作,而在onSocket:willDisconnectWithError 释放则不安全
- -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- -(BOOL)onSocketWillConnect:(AsyncSocket *)sock;
- -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port;
- 当socket连接正准备读和写的时候调用,host属性是一个IP地址,而不是一个DNS 名称
- -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag;
- 当socket已完成所要求的数据读入内存时调用,如果有错误则不调用
- -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag;
- 当一个socket读取数据,但尚未完成读操作的时候调用,如果使用 readToData: or readToLength: 方法 会发生,可以被用来更新进度条等东西
- -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
- 当一个socket已完成请求数据的写入时候调用
- -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- 当一个socket写入一些数据,但还没有完成整个写入时调用,它可以用来更新进度条等东西
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length
- 使用读操作已超时但还没完成时调用,此方法允许随意延迟超时,如果返回一个正的时间间隔,读取的超时将有一定量的扩展,如果不实现这个方法,或会像往常一样返回一个负的时间间隔,elapsed参数是 原超时的总和,加上先前通过这种方法添加的任何补充, length参数是 读操作到目前为止已读取的字节数, 注意,如果返回正数的话,这个方法可能被一个单独的读取多次调用
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length;
- 如果一个写操作已达到其超时但还没完成时调用,同上
- -(void)onSocketDidSecure:(AsyncSocket *)sock;
- 在socket成功完成ssl/tls协商时调用,此方法除非你使用提供startTLS方法时候才调用,
- 如果ssl/tls是无效的证书,socket将会立即关闭,onSocket:willDisconnectWithError:代理方法竟会与特定的ssl错误代码一起调用
- -(BOOL)canSafelySetDelegate
- 用来查看在改变它之前,是否带有与当前的委托有悬而未决的业务(读/写)。当然,应在安全连接或接受委托之前改变委托
- 一旦接收或连接方法之一被调用,AsyncSocket实例会被锁定,其他接收/连接方法在没有先断开socket不会被调用
- 如果尝试失败或超时,这些方法要么返回NO 要么调用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect
- 当传入的连接被接受,AsyncSocket调用多个委托方法。这些方法按照时间顺序排列:
- 1.onSocket:didAcceptNewSocket:
- 2.onSocket:wantsRunLoopForNewSocket:
- 3. onSocketWillConnect:
- 你的服务器的代码将需要保留公认的socket(如果要接受它),最好的地方是要做到这一点可能在onSocket:didAcceptNewSocket:方法
- 在读和写流已经为新接受的socket设置,onSocket:didConnectToHost:port 方法将在适当的运行循环调用
- 多线程注意,如果要想通过实施onSocket:wantsRunLoopForNewSocket:,移动另一个新接受的socket去到另一个循环的socket。然后,应该在调用读和写或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否则读和写时间原定于不正确的runloop,混乱可能会随之而来
- -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr;
- 告诉socket开始听取和接受制定端口上的连接,当一个连接到来的时候,AsyncSocket实例将调用各种委托方法,socket将听取所有可用的接口(wifi,以太网等)
- -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr;
- 连接给定的主机和端口,主机hostname可以是域名或者是Ip地址
- -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr;
- 连接到一个给定的地址,制定一个sockaddr结构包裹住一个NSData对象,例如,NSData对象从NSNetService的地址方法返回,如果有一个现有的sockaddr结构,可以将它转换到一个NSData对象,像这样:
- struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
- struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
- -(void)disconnect;
- 立即断开,任何未处理的读或写都将被丢弃
- 如果socket还没有断开,在这个方法返回之前,onSocketDidDisconnect 委托方法将会被立即调用
- 注意推荐释放AsyncSocket实例的方式:
- [asyncSocket setDelegate:nil];
- [asyncSocket disconnect];
- [asyncSocket release];
- -(void)disconnectAfterReading;
- 在已经完成了所有悬而未决的读取时 断开,在调用之后,读取和写入方法将无用,socket将断开 即使仍有待写入
- - (NSString *)connectedHost;
- - (UInt16)connectedPort;
- - (NSString *)localHost;
- - (UInt16)localPort;
- 返回本地和远程主机和端口给连接的socket,如果没有连接会返回nil或0,主机将会是一个IP地址
- -(NSData *)connectedAddress
- -(NSData *)localAddresss
- 返回本地和远程的地址给连接的socket,指定一个socketaddr结构包裹在一个NSData对象
- readData和writeData方法不会是block(它们是异步的)
- 当读完成 onSocket:didReadData:withTag: 委托方法时调用
- 当写完成 onSocket:didWriteDataWithTag: 委托方法时调用
- 可以选择任何读/写操作的超时设置(为了不超时,使用负时间间隔。)
- 如果读/写操作超时,相应的 onSocket:shouldTimeout...委托方法被调用去选择性地允许我们去延长超时
- 超时后,onSocket:willDisconnectWithError: 方法被调用,紧接着是 onSocketDidDisconnect
- tag是为了方便,可以使用它作为数组的索引、步数、state id 、指针等
- -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag;
- 读取socket上第一次成为可用的字节,如果timeout值是负数的,读操作将不使用timeout
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag;
- 读取socket上第一次成为可用的字节
- 字节将被追加到给定的字节缓冲区,从给定的偏移量开始
- 如果需要,给定的缓冲区大小将会自动增加
- 如果timeout值是负数的,读操作将不使用timeout
- 如果缓冲区为空,socket会为我们创建一个缓冲区
- 如果bufferOffset是大于给定的缓冲区的长度,该方法将无用,委托将不会被调用
- 如果你传递一个缓冲区,当AsyncSocket在使用它的时候你不能以任何方式改变它
- 完成之后,onSocket:didReadData:withTag 返回的数据将是一个给定的缓冲区的子集
- 也就是说,它将会被引用到被追加的给定的缓冲区的字节
- -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取给定的字节数,如果length为0,方法将无用,委托将不会被调用
- -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取给定的字节数,在给定的偏移开始,字节将被追加到给定的字节缓冲区
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的"data"参数
- 如果传递0或者0长度的数据,"data"参数,该方法将无用,委托将不会被调用
- 从socket读取一行,使用"data"参数作为行的分隔符 (如HTTP的CRLF)
- 注意,此方法不是字符集,因此,如果一个分隔符出现,它自然可以作为进行编码的一部分,读取将提前结束
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的“data”参数,在给定的偏移量开始,字节将被追加到给定的字节缓冲区。
- 从socket读取一行,使用"data"参数作为行的分隔符(如HTTP的CRLF)
- -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag;
- 将data写入socket,当完成的时候委托被调用
- - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- 返回当前读或写的进度,从0.0 到 1.0 或者 如果没有读/写的时候返回Nan(使用isNan来检查)
- tag、done、total如果不为空的话,它们将会被填补
- - (void)startTLS:(NSDictionary *)tlsSettings;
- 确保使用ssl/tls连接
- 这方法可被随时调用,tls握手将会发生在所有悬而未决的读/写完成之后。这紧跟着一个发送依赖 StartTLS消息的协议选项,在排队升级到TLS的同一时间,而不必等待写入完成。在这个方法被调用后,任何读写计划 将会发生在安全链接
- 对于可能的keys和TLS设置的值是有据可查的
- 一些可能的keys是:
- * - kCFStreamSSLLevel
- * - kCFStreamSSLAllowsExpiredCertificates
- * - kCFStreamSSLAllowsExpiredRoots
- * - kCFStreamSSLAllowsAnyRoot
- * - kCFStreamSSLValidatesCertificateChain
- * - kCFStreamSSLPeerName
- * - kCFStreamSSLCertificates
- * - kCFStreamSSLIsServer
- 如果你传递空或者空字典,将使用默认的字典
- 默认设置将检查以确保由签署可信的第三方证书机构和没有过期的远程连接的证书
- 然而,它不会验证证书上的名字,除非你给它一个名字,通过kCFStreamSSLPeerName键去验证
- 这对安全的影响是重要的理解
- 想象一下你正试图创建一个到MySecureServer.com的安全连接,但因为一个被攻击的DNS服务器,所以你的socket被定向到MaliciousServer.com
- 如果你只是使用默认设置,MaliciousServer.com 有一个有效的证书
- 默认设置将无法监测到任何问题,因为证书是有效的
- 在这个特殊的情况下,要妥善保护你的连接,应设置kCFStreamSSLPeerName性质为MySecureServer.com.
- 如果事前你不知道对等的名字的远程主机(例如,你不确认它是domain.com" or "www.domain.com"),那么你可以使用默认设置来验证证书,然后在获得验证的发行后使用X509Certificate类来验证,X509Certificate类的CocoaAsyncSocket开源项目的一部分
- -(void)enablePrebuffering
- 对于处理readDataToData请求,数据是必须从socket以小增量的方式读取出来的
- 性能通过允许AsyncSocket去一次性读大块的数据和存储任何一个小的内部缓冲区溢出的东西来大大提高
- 这被称为预缓冲,就好像一些数据在你要求它之前就可能被读取出来
- 如果你经常使用readDataToData,使用预缓冲会有更好的性能,尤其是在iphone上
- 默认的预缓冲状态是由DEFAULT_PREBUFFERING 定义控制的,强烈建议设置其为yes
- 这方法存在一些预缓冲需要一些不可预见的原因被默认禁用的情况,这时,这种方法存在允许当就绪时,可轻松启用预缓冲
- -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
- 当你创建一个AsyncSocket,它被添加到当前线程runloop
- 对于手动创建的socket,在线程上你打算使用它,它是最容易简单的创建的线程上的socket
- 当一个新的socket被接受,委托方法 onSocket:wantsRunLoopForNewSocket 会被调用 允许你在一个单独的线程上放置socket,这个工作最好结合在同一个线程池设计
- 如果,但是,在一个单独的线程上,在之后的时间,你需要移动一个socket,这个方法可以用来完成任务
- 此方法必须从 当前运行的 线程/runloop 的socket 调用
- 注意:此方法调用后,所有进一步的方法应该从给定的runloop上调用这个对象
- 此外,所有委托调用将会发送到给定的runloop
- - (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- - (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- - (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
- 允许你配置 socket 使用的 运行循环模式
- 运行循环模式设置默认是NSRunLoopCommonModes
- 如果你想你的socket 在其他模式下继续操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes
- 可接受的socket将自动 继承相同的运行循环模式就像侦听socket
- 注意:NSRunLoopCommonModes 定义在10.5,对于之前的版本可使用 kCFRunLoopCommonModes
- -(NSArray *)runLoopModes
- 返回当前正在运行的循环模式的AsyncSocket实例, run loop modes的默认设置是NSDefaultRunLoopMode
- -(NSData *)unreadData;
- 一个错误的事件,在 onSocket:willDisconnectWithError: 将会被调用 去读取留在socket上的任何数据
- + (NSData *)CRLFData; // 0x0D0A
- 各方法的解析
- -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- -(void)onSocketDidDisconnect:(ASyncSocket *)sock;
- 当socket由于或没有错误而断开连接,如果你想要在断开连接后release socket,在此方法工作,而在onSocket:willDisconnectWithError 释放则不安全
- -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- -(BOOL)onSocketWillConnect:(AsyncSocket *)sock;
- -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port;
- 当socket连接正准备读和写的时候调用,host属性是一个IP地址,而不是一个DNS 名称
- -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag;
- 当socket已完成所要求的数据读入内存时调用,如果有错误则不调用
- -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag;
- 当一个socket读取数据,但尚未完成读操作的时候调用,如果使用 readToData: or readToLength: 方法 会发生,可以被用来更新进度条等东西
- -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
- 当一个socket已完成请求数据的写入时候调用
- -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- 当一个socket写入一些数据,但还没有完成整个写入时调用,它可以用来更新进度条等东西
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length
- 使用读操作已超时但还没完成时调用,此方法允许随意延迟超时,如果返回一个正的时间间隔,读取的超时将有一定量的扩展,如果不实现这个方法,或会像往常一样返回一个负的时间间隔,elapsed参数是 原超时的总和,加上先前通过这种方法添加的任何补充, length参数是 读操作到目前为止已读取的字节数, 注意,如果返回正数的话,这个方法可能被一个单独的读取多次调用
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length;
- 如果一个写操作已达到其超时但还没完成时调用,同上
- -(void)onSocketDidSecure:(AsyncSocket *)sock;
- 在socket成功完成ssl/tls协商时调用,此方法除非你使用提供startTLS方法时候才调用,
- 如果ssl/tls是无效的证书,socket将会立即关闭,onSocket:willDisconnectWithError:代理方法竟会与特定的ssl错误代码一起调用
- -(BOOL)canSafelySetDelegate
- 用来查看在改变它之前,是否带有与当前的委托有悬而未决的业务(读/写)。当然,应在安全连接或接受委托之前改变委托
- 一旦接收或连接方法之一被调用,AsyncSocket实例会被锁定,其他接收/连接方法在没有先断开socket不会被调用
- 如果尝试失败或超时,这些方法要么返回NO 要么调用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect
- 当传入的连接被接受,AsyncSocket调用多个委托方法。这些方法按照时间顺序排列:
- 1.onSocket:didAcceptNewSocket:
- 2.onSocket:wantsRunLoopForNewSocket:
- 3. onSocketWillConnect:
- 你的服务器的代码将需要保留公认的socket(如果要接受它),最好的地方是要做到这一点可能在onSocket:didAcceptNewSocket:方法
- 在读和写流已经为新接受的socket设置,onSocket:didConnectToHost:port 方法将在适当的运行循环调用
- 多线程注意,如果要想通过实施onSocket:wantsRunLoopForNewSocket:,移动另一个新接受的socket去到另一个循环的socket。然后,应该在调用读和写或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否则读和写时间原定于不正确的runloop,混乱可能会随之而来
- -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr;
- 告诉socket开始听取和接受制定端口上的连接,当一个连接到来的时候,AsyncSocket实例将调用各种委托方法,socket将听取所有可用的接口(wifi,以太网等)
- -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr;
- 连接给定的主机和端口,主机hostname可以是域名或者是Ip地址
- -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr;
- 连接到一个给定的地址,制定一个sockaddr结构包裹住一个NSData对象,例如,NSData对象从NSNetService的地址方法返回,如果有一个现有的sockaddr结构,可以将它转换到一个NSData对象,像这样:
- struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
- struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
- -(void)disconnect;
- 立即断开,任何未处理的读或写都将被丢弃
- 如果socket还没有断开,在这个方法返回之前,onSocketDidDisconnect 委托方法将会被立即调用
- 注意推荐释放AsyncSocket实例的方式:
- [asyncSocket setDelegate:nil];
- [asyncSocket disconnect];
- [asyncSocket release];
- -(void)disconnectAfterReading;
- 在已经完成了所有悬而未决的读取时 断开,在调用之后,读取和写入方法将无用,socket将断开 即使仍有待写入
- - (NSString *)connectedHost;
- - (UInt16)connectedPort;
- - (NSString *)localHost;
- - (UInt16)localPort;
- 返回本地和远程主机和端口给连接的socket,如果没有连接会返回nil或0,主机将会是一个IP地址
- -(NSData *)connectedAddress
- -(NSData *)localAddresss
- 返回本地和远程的地址给连接的socket,指定一个socketaddr结构包裹在一个NSData对象
- readData和writeData方法不会是block(它们是异步的)
- 当读完成 onSocket:didReadData:withTag: 委托方法时调用
- 当写完成 onSocket:didWriteDataWithTag: 委托方法时调用
- 可以选择任何读/写操作的超时设置(为了不超时,使用负时间间隔。)
- 如果读/写操作超时,相应的 onSocket:shouldTimeout...委托方法被调用去选择性地允许我们去延长超时
- 超时后,onSocket:willDisconnectWithError: 方法被调用,紧接着是 onSocketDidDisconnect
- tag是为了方便,可以使用它作为数组的索引、步数、state id 、指针等
- -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag;
- 读取socket上第一次成为可用的字节,如果timeout值是负数的,读操作将不使用timeout
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag;
- 读取socket上第一次成为可用的字节
- 字节将被追加到给定的字节缓冲区,从给定的偏移量开始
- 如果需要,给定的缓冲区大小将会自动增加
- 如果timeout值是负数的,读操作将不使用timeout
- 如果缓冲区为空,socket会为我们创建一个缓冲区
- 如果bufferOffset是大于给定的缓冲区的长度,该方法将无用,委托将不会被调用
- 如果你传递一个缓冲区,当AsyncSocket在使用它的时候你不能以任何方式改变它
- 完成之后,onSocket:didReadData:withTag 返回的数据将是一个给定的缓冲区的子集
- 也就是说,它将会被引用到被追加的给定的缓冲区的字节
- -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取给定的字节数,如果length为0,方法将无用,委托将不会被调用
- -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取给定的字节数,在给定的偏移开始,字节将被追加到给定的字节缓冲区
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的"data"参数
- 如果传递0或者0长度的数据,"data"参数,该方法将无用,委托将不会被调用
- 从socket读取一行,使用"data"参数作为行的分隔符 (如HTTP的CRLF)
- 注意,此方法不是字符集,因此,如果一个分隔符出现,它自然可以作为进行编码的一部分,读取将提前结束
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的“data”参数,在给定的偏移量开始,字节将被追加到给定的字节缓冲区。
- 从socket读取一行,使用"data"参数作为行的分隔符(如HTTP的CRLF)
- -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag;
- 将data写入socket,当完成的时候委托被调用
- - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- 返回当前读或写的进度,从0.0 到 1.0 或者 如果没有读/写的时候返回Nan(使用isNan来检查)
- tag、done、total如果不为空的话,它们将会被填补
- - (void)startTLS:(NSDictionary *)tlsSettings;
- 确保使用ssl/tls连接
- 这方法可被随时调用,tls握手将会发生在所有悬而未决的读/写完成之后。这紧跟着一个发送依赖 StartTLS消息的协议选项,在排队升级到TLS的同一时间,而不必等待写入完成。在这个方法被调用后,任何读写计划 将会发生在安全链接
- 对于可能的keys和TLS设置的值是有据可查的
- 一些可能的keys是:
- * - kCFStreamSSLLevel
- * - kCFStreamSSLAllowsExpiredCertificates
- * - kCFStreamSSLAllowsExpiredRoots
- * - kCFStreamSSLAllowsAnyRoot
- * - kCFStreamSSLValidatesCertificateChain
- * - kCFStreamSSLPeerName
- * - kCFStreamSSLCertificates
- * - kCFStreamSSLIsServer
- 如果你传递空或者空字典,将使用默认的字典
- 默认设置将检查以确保由签署可信的第三方证书机构和没有过期的远程连接的证书
- 然而,它不会验证证书上的名字,除非你给它一个名字,通过kCFStreamSSLPeerName键去验证
- 这对安全的影响是重要的理解
- 想象一下你正试图创建一个到MySecureServer.com的安全连接,但因为一个被攻击的DNS服务器,所以你的socket被定向到MaliciousServer.com
- 如果你只是使用默认设置,MaliciousServer.com 有一个有效的证书
- 默认设置将无法监测到任何问题,因为证书是有效的
- 在这个特殊的情况下,要妥善保护你的连接,应设置kCFStreamSSLPeerName性质为MySecureServer.com.
- 如果事前你不知道对等的名字的远程主机(例如,你不确认它是domain.com" or "www.domain.com"),那么你可以使用默认设置来验证证书,然后在获得验证的发行后使用X509Certificate类来验证,X509Certificate类的CocoaAsyncSocket开源项目的一部分
- -(void)enablePrebuffering
- 对于处理readDataToData请求,数据是必须从socket以小增量的方式读取出来的
- 性能通过允许AsyncSocket去一次性读大块的数据和存储任何一个小的内部缓冲区溢出的东西来大大提高
- 这被称为预缓冲,就好像一些数据在你要求它之前就可能被读取出来
- 如果你经常使用readDataToData,使用预缓冲会有更好的性能,尤其是在iphone上
- 默认的预缓冲状态是由DEFAULT_PREBUFFERING 定义控制的,强烈建议设置其为yes
- 这方法存在一些预缓冲需要一些不可预见的原因被默认禁用的情况,这时,这种方法存在允许当就绪时,可轻松启用预缓冲
- -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
- 当你创建一个AsyncSocket,它被添加到当前线程runloop
- 对于手动创建的socket,在线程上你打算使用它,它是最容易简单的创建的线程上的socket
- 当一个新的socket被接受,委托方法 onSocket:wantsRunLoopForNewSocket 会被调用 允许你在一个单独的线程上放置socket,这个工作最好结合在同一个线程池设计
- 如果,但是,在一个单独的线程上,在之后的时间,你需要移动一个socket,这个方法可以用来完成任务
- 此方法必须从 当前运行的 线程/runloop 的socket 调用
- 注意:此方法调用后,所有进一步的方法应该从给定的runloop上调用这个对象
- 此外,所有委托调用将会发送到给定的runloop
- - (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- - (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- - (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
- 允许你配置 socket 使用的 运行循环模式
- 运行循环模式设置默认是NSRunLoopCommonModes
- 如果你想你的socket 在其他模式下继续操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes
- 可接受的socket将自动 继承相同的运行循环模式就像侦听socket
- 注意:NSRunLoopCommonModes 定义在10.5,对于之前的版本可使用 kCFRunLoopCommonModes
- -(NSArray *)runLoopModes
- 返回当前正在运行的循环模式的AsyncSocket实例, run loop modes的默认设置是NSDefaultRunLoopMode
- -(NSData *)unreadData;
- 一个错误的事件,在 onSocket:willDisconnectWithError: 将会被调用 去读取留在socket上的任何数据
- + (NSData *)CRLFData; // 0x0D0A
- 各方法的解析
- -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- -(void)onSocketDidDisconnect:(ASyncSocket *)sock;
- 当socket由于或没有错误而断开连接,如果你想要在断开连接后release socket,在此方法工作,而在onSocket:willDisconnectWithError 释放则不安全
- -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- -(BOOL)onSocketWillConnect:(AsyncSocket *)sock;
- -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port;
- 当socket连接正准备读和写的时候调用,host属性是一个IP地址,而不是一个DNS 名称
- -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag;
- 当socket已完成所要求的数据读入内存时调用,如果有错误则不调用
- -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag;
- 当一个socket读取数据,但尚未完成读操作的时候调用,如果使用 readToData: or readToLength: 方法 会发生,可以被用来更新进度条等东西
- -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
- 当一个socket已完成请求数据的写入时候调用
- -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- 当一个socket写入一些数据,但还没有完成整个写入时调用,它可以用来更新进度条等东西
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length
- 使用读操作已超时但还没完成时调用,此方法允许随意延迟超时,如果返回一个正的时间间隔,读取的超时将有一定量的扩展,如果不实现这个方法,或会像往常一样返回一个负的时间间隔,elapsed参数是 原超时的总和,加上先前通过这种方法添加的任何补充, length参数是 读操作到目前为止已读取的字节数, 注意,如果返回正数的话,这个方法可能被一个单独的读取多次调用
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length;
- 如果一个写操作已达到其超时但还没完成时调用,同上
- -(void)onSocketDidSecure:(AsyncSocket *)sock;
- 在socket成功完成ssl/tls协商时调用,此方法除非你使用提供startTLS方法时候才调用,
- 如果ssl/tls是无效的证书,socket将会立即关闭,onSocket:willDisconnectWithError:代理方法竟会与特定的ssl错误代码一起调用
- -(BOOL)canSafelySetDelegate
- 用来查看在改变它之前,是否带有与当前的委托有悬而未决的业务(读/写)。当然,应在安全连接或接受委托之前改变委托
- 一旦接收或连接方法之一被调用,AsyncSocket实例会被锁定,其他接收/连接方法在没有先断开socket不会被调用
- 如果尝试失败或超时,这些方法要么返回NO 要么调用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect
- 当传入的连接被接受,AsyncSocket调用多个委托方法。这些方法按照时间顺序排列:
- 1.onSocket:didAcceptNewSocket:
- 2.onSocket:wantsRunLoopForNewSocket:
- 3. onSocketWillConnect:
- 你的服务器的代码将需要保留公认的socket(如果要接受它),最好的地方是要做到这一点可能在onSocket:didAcceptNewSocket:方法
- 在读和写流已经为新接受的socket设置,onSocket:didConnectToHost:port 方法将在适当的运行循环调用
- 多线程注意,如果要想通过实施onSocket:wantsRunLoopForNewSocket:,移动另一个新接受的socket去到另一个循环的socket。然后,应该在调用读和写或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否则读和写时间原定于不正确的runloop,混乱可能会随之而来
- -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr;
- 告诉socket开始听取和接受制定端口上的连接,当一个连接到来的时候,AsyncSocket实例将调用各种委托方法,socket将听取所有可用的接口(wifi,以太网等)
- -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr;
- 连接给定的主机和端口,主机hostname可以是域名或者是Ip地址
- -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr;
- 连接到一个给定的地址,制定一个sockaddr结构包裹住一个NSData对象,例如,NSData对象从NSNetService的地址方法返回,如果有一个现有的sockaddr结构,可以将它转换到一个NSData对象,像这样:
- struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
- struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
- -(void)disconnect;
- 立即断开,任何未处理的读或写都将被丢弃
- 如果socket还没有断开,在这个方法返回之前,onSocketDidDisconnect 委托方法将会被立即调用
- 注意推荐释放AsyncSocket实例的方式:
- [asyncSocket setDelegate:nil];
- [asyncSocket disconnect];
- [asyncSocket release];
- -(void)disconnectAfterReading;
- 在已经完成了所有悬而未决的读取时 断开,在调用之后,读取和写入方法将无用,socket将断开 即使仍有待写入
- - (NSString *)connectedHost;
- - (UInt16)connectedPort;
- - (NSString *)localHost;
- - (UInt16)localPort;
- 返回本地和远程主机和端口给连接的socket,如果没有连接会返回nil或0,主机将会是一个IP地址
- -(NSData *)connectedAddress
- -(NSData *)localAddresss
- 返回本地和远程的地址给连接的socket,指定一个socketaddr结构包裹在一个NSData对象
- readData和writeData方法不会是block(它们是异步的)
- 当读完成 onSocket:didReadData:withTag: 委托方法时调用
- 当写完成 onSocket:didWriteDataWithTag: 委托方法时调用
- 可以选择任何读/写操作的超时设置(为了不超时,使用负时间间隔。)
- 如果读/写操作超时,相应的 onSocket:shouldTimeout...委托方法被调用去选择性地允许我们去延长超时
- 超时后,onSocket:willDisconnectWithError: 方法被调用,紧接着是 onSocketDidDisconnect
- tag是为了方便,可以使用它作为数组的索引、步数、state id 、指针等
- -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag;
- 读取socket上第一次成为可用的字节,如果timeout值是负数的,读操作将不使用timeout
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag;
- 读取socket上第一次成为可用的字节
- 字节将被追加到给定的字节缓冲区,从给定的偏移量开始
- 如果需要,给定的缓冲区大小将会自动增加
- 如果timeout值是负数的,读操作将不使用timeout
- 如果缓冲区为空,socket会为我们创建一个缓冲区
- 如果bufferOffset是大于给定的缓冲区的长度,该方法将无用,委托将不会被调用
- 如果你传递一个缓冲区,当AsyncSocket在使用它的时候你不能以任何方式改变它
- 完成之后,onSocket:didReadData:withTag 返回的数据将是一个给定的缓冲区的子集
- 也就是说,它将会被引用到被追加的给定的缓冲区的字节
- -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取给定的字节数,如果length为0,方法将无用,委托将不会被调用
- -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取给定的字节数,在给定的偏移开始,字节将被追加到给定的字节缓冲区
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的"data"参数
- 如果传递0或者0长度的数据,"data"参数,该方法将无用,委托将不会被调用
- 从socket读取一行,使用"data"参数作为行的分隔符 (如HTTP的CRLF)
- 注意,此方法不是字符集,因此,如果一个分隔符出现,它自然可以作为进行编码的一部分,读取将提前结束
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的“data”参数,在给定的偏移量开始,字节将被追加到给定的字节缓冲区。
- 从socket读取一行,使用"data"参数作为行的分隔符(如HTTP的CRLF)
- -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag;
- 将data写入socket,当完成的时候委托被调用
- - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- 返回当前读或写的进度,从0.0 到 1.0 或者 如果没有读/写的时候返回Nan(使用isNan来检查)
- tag、done、total如果不为空的话,它们将会被填补
- - (void)startTLS:(NSDictionary *)tlsSettings;
- 确保使用ssl/tls连接
- 这方法可被随时调用,tls握手将会发生在所有悬而未决的读/写完成之后。这紧跟着一个发送依赖 StartTLS消息的协议选项,在排队升级到TLS的同一时间,而不必等待写入完成。在这个方法被调用后,任何读写计划 将会发生在安全链接
- 对于可能的keys和TLS设置的值是有据可查的
- 一些可能的keys是:
- * - kCFStreamSSLLevel
- * - kCFStreamSSLAllowsExpiredCertificates
- * - kCFStreamSSLAllowsExpiredRoots
- * - kCFStreamSSLAllowsAnyRoot
- * - kCFStreamSSLValidatesCertificateChain
- * - kCFStreamSSLPeerName
- * - kCFStreamSSLCertificates
- * - kCFStreamSSLIsServer
- 如果你传递空或者空字典,将使用默认的字典
- 默认设置将检查以确保由签署可信的第三方证书机构和没有过期的远程连接的证书
- 然而,它不会验证证书上的名字,除非你给它一个名字,通过kCFStreamSSLPeerName键去验证
- 这对安全的影响是重要的理解
- 想象一下你正试图创建一个到MySecureServer.com的安全连接,但因为一个被攻击的DNS服务器,所以你的socket被定向到MaliciousServer.com
- 如果你只是使用默认设置,MaliciousServer.com 有一个有效的证书
- 默认设置将无法监测到任何问题,因为证书是有效的
- 在这个特殊的情况下,要妥善保护你的连接,应设置kCFStreamSSLPeerName性质为MySecureServer.com.
- 如果事前你不知道对等的名字的远程主机(例如,你不确认它是domain.com" or "www.domain.com"),那么你可以使用默认设置来验证证书,然后在获得验证的发行后使用X509Certificate类来验证,X509Certificate类的CocoaAsyncSocket开源项目的一部分
- -(void)enablePrebuffering
- 对于处理readDataToData请求,数据是必须从socket以小增量的方式读取出来的
- 性能通过允许AsyncSocket去一次性读大块的数据和存储任何一个小的内部缓冲区溢出的东西来大大提高
- 这被称为预缓冲,就好像一些数据在你要求它之前就可能被读取出来
- 如果你经常使用readDataToData,使用预缓冲会有更好的性能,尤其是在iphone上
- 默认的预缓冲状态是由DEFAULT_PREBUFFERING 定义控制的,强烈建议设置其为yes
- 这方法存在一些预缓冲需要一些不可预见的原因被默认禁用的情况,这时,这种方法存在允许当就绪时,可轻松启用预缓冲
- -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
- 当你创建一个AsyncSocket,它被添加到当前线程runloop
- 对于手动创建的socket,在线程上你打算使用它,它是最容易简单的创建的线程上的socket
- 当一个新的socket被接受,委托方法 onSocket:wantsRunLoopForNewSocket 会被调用 允许你在一个单独的线程上放置socket,这个工作最好结合在同一个线程池设计
- 如果,但是,在一个单独的线程上,在之后的时间,你需要移动一个socket,这个方法可以用来完成任务
- 此方法必须从 当前运行的 线程/runloop 的socket 调用
- 注意:此方法调用后,所有进一步的方法应该从给定的runloop上调用这个对象
- 此外,所有委托调用将会发送到给定的runloop
- - (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- - (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- - (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
- 允许你配置 socket 使用的 运行循环模式
- 运行循环模式设置默认是NSRunLoopCommonModes
- 如果你想你的socket 在其他模式下继续操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes
- 可接受的socket将自动 继承相同的运行循环模式就像侦听socket
- 注意:NSRunLoopCommonModes 定义在10.5,对于之前的版本可使用 kCFRunLoopCommonModes
- -(NSArray *)runLoopModes
- 返回当前正在运行的循环模式的AsyncSocket实例, run loop modes的默认设置是NSDefaultRunLoopMode
- -(NSData *)unreadData;
- 一个错误的事件,在 onSocket:willDisconnectWithError: 将会被调用 去读取留在socket上的任何数据
- + (NSData *)CRLFData; // 0x0D0A
- 各方法的解析
- -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- 发生错误,socket关闭,可以在call-back过程调用"unreadData"去取得socket的最后的数据字节,当连接的时候,该委托方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前调用
- -(void)onSocketDidDisconnect:(ASyncSocket *)sock;
- 当socket由于或没有错误而断开连接,如果你想要在断开连接后release socket,在此方法工作,而在onSocket:willDisconnectWithError 释放则不安全
- -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- 当产生一个socket去处理连接时调用,此方法会返回 线程上的run-loop 的新的socket和其应处理的委托,如果省略,则使用[NSRunLoop cunrrentRunLoop]
- -(BOOL)onSocketWillConnect:(AsyncSocket *)sock;
- -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port;
- 当socket连接正准备读和写的时候调用,host属性是一个IP地址,而不是一个DNS 名称
- -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag;
- 当socket已完成所要求的数据读入内存时调用,如果有错误则不调用
- -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag;
- 当一个socket读取数据,但尚未完成读操作的时候调用,如果使用 readToData: or readToLength: 方法 会发生,可以被用来更新进度条等东西
- -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
- 当一个socket已完成请求数据的写入时候调用
- -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- 当一个socket写入一些数据,但还没有完成整个写入时调用,它可以用来更新进度条等东西
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length
- 使用读操作已超时但还没完成时调用,此方法允许随意延迟超时,如果返回一个正的时间间隔,读取的超时将有一定量的扩展,如果不实现这个方法,或会像往常一样返回一个负的时间间隔,elapsed参数是 原超时的总和,加上先前通过这种方法添加的任何补充, length参数是 读操作到目前为止已读取的字节数, 注意,如果返回正数的话,这个方法可能被一个单独的读取多次调用
- -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length;
- 如果一个写操作已达到其超时但还没完成时调用,同上
- -(void)onSocketDidSecure:(AsyncSocket *)sock;
- 在socket成功完成ssl/tls协商时调用,此方法除非你使用提供startTLS方法时候才调用,
- 如果ssl/tls是无效的证书,socket将会立即关闭,onSocket:willDisconnectWithError:代理方法竟会与特定的ssl错误代码一起调用
- -(BOOL)canSafelySetDelegate
- 用来查看在改变它之前,是否带有与当前的委托有悬而未决的业务(读/写)。当然,应在安全连接或接受委托之前改变委托
- 一旦接收或连接方法之一被调用,AsyncSocket实例会被锁定,其他接收/连接方法在没有先断开socket不会被调用
- 如果尝试失败或超时,这些方法要么返回NO 要么调用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect
- 当传入的连接被接受,AsyncSocket调用多个委托方法。这些方法按照时间顺序排列:
- 1.onSocket:didAcceptNewSocket:
- 2.onSocket:wantsRunLoopForNewSocket:
- 3. onSocketWillConnect:
- 你的服务器的代码将需要保留公认的socket(如果要接受它),最好的地方是要做到这一点可能在onSocket:didAcceptNewSocket:方法
- 在读和写流已经为新接受的socket设置,onSocket:didConnectToHost:port 方法将在适当的运行循环调用
- 多线程注意,如果要想通过实施onSocket:wantsRunLoopForNewSocket:,移动另一个新接受的socket去到另一个循环的socket。然后,应该在调用读和写或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否则读和写时间原定于不正确的runloop,混乱可能会随之而来
- -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr;
- 告诉socket开始听取和接受制定端口上的连接,当一个连接到来的时候,AsyncSocket实例将调用各种委托方法,socket将听取所有可用的接口(wifi,以太网等)
- -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr;
- 连接给定的主机和端口,主机hostname可以是域名或者是Ip地址
- -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr;
- 连接到一个给定的地址,制定一个sockaddr结构包裹住一个NSData对象,例如,NSData对象从NSNetService的地址方法返回,如果有一个现有的sockaddr结构,可以将它转换到一个NSData对象,像这样:
- struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];
- struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
- -(void)disconnect;
- 立即断开,任何未处理的读或写都将被丢弃
- 如果socket还没有断开,在这个方法返回之前,onSocketDidDisconnect 委托方法将会被立即调用
- 注意推荐释放AsyncSocket实例的方式:
- [asyncSocket setDelegate:nil];
- [asyncSocket disconnect];
- [asyncSocket release];
- -(void)disconnectAfterReading;
- 在已经完成了所有悬而未决的读取时 断开,在调用之后,读取和写入方法将无用,socket将断开 即使仍有待写入
- - (NSString *)connectedHost;
- - (UInt16)connectedPort;
- - (NSString *)localHost;
- - (UInt16)localPort;
- 返回本地和远程主机和端口给连接的socket,如果没有连接会返回nil或0,主机将会是一个IP地址
- -(NSData *)connectedAddress
- -(NSData *)localAddresss
- 返回本地和远程的地址给连接的socket,指定一个socketaddr结构包裹在一个NSData对象
- readData和writeData方法不会是block(它们是异步的)
- 当读完成 onSocket:didReadData:withTag: 委托方法时调用
- 当写完成 onSocket:didWriteDataWithTag: 委托方法时调用
- 可以选择任何读/写操作的超时设置(为了不超时,使用负时间间隔。)
- 如果读/写操作超时,相应的 onSocket:shouldTimeout...委托方法被调用去选择性地允许我们去延长超时
- 超时后,onSocket:willDisconnectWithError: 方法被调用,紧接着是 onSocketDidDisconnect
- tag是为了方便,可以使用它作为数组的索引、步数、state id 、指针等
- -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag;
- 读取socket上第一次成为可用的字节,如果timeout值是负数的,读操作将不使用timeout
- - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag;
- 读取socket上第一次成为可用的字节
- 字节将被追加到给定的字节缓冲区,从给定的偏移量开始
- 如果需要,给定的缓冲区大小将会自动增加
- 如果timeout值是负数的,读操作将不使用timeout
- 如果缓冲区为空,socket会为我们创建一个缓冲区
- 如果bufferOffset是大于给定的缓冲区的长度,该方法将无用,委托将不会被调用
- 如果你传递一个缓冲区,当AsyncSocket在使用它的时候你不能以任何方式改变它
- 完成之后,onSocket:didReadData:withTag 返回的数据将是一个给定的缓冲区的子集
- 也就是说,它将会被引用到被追加的给定的缓冲区的字节
- -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取给定的字节数,如果length为0,方法将无用,委托将不会被调用
- -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取给定的字节数,在给定的偏移开始,字节将被追加到给定的字节缓冲区
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的"data"参数
- 如果传递0或者0长度的数据,"data"参数,该方法将无用,委托将不会被调用
- 从socket读取一行,使用"data"参数作为行的分隔符 (如HTTP的CRLF)
- 注意,此方法不是字符集,因此,如果一个分隔符出现,它自然可以作为进行编码的一部分,读取将提前结束
- -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag;
- 读取字节直到(包括)传入的作为分隔的“data”参数,在给定的偏移量开始,字节将被追加到给定的字节缓冲区。
- 从socket读取一行,使用"data"参数作为行的分隔符(如HTTP的CRLF)
- -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag;
- 将data写入socket,当完成的时候委托被调用
- - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total;
- 返回当前读或写的进度,从0.0 到 1.0 或者 如果没有读/写的时候返回Nan(使用isNan来检查)
- tag、done、total如果不为空的话,它们将会被填补
- - (void)startTLS:(NSDictionary *)tlsSettings;
- 确保使用ssl/tls连接
- 这方法可被随时调用,tls握手将会发生在所有悬而未决的读/写完成之后。这紧跟着一个发送依赖 StartTLS消息的协议选项,在排队升级到TLS的同一时间,而不必等待写入完成。在这个方法被调用后,任何读写计划 将会发生在安全链接
- 对于可能的keys和TLS设置的值是有据可查的
- 一些可能的keys是:
- * - kCFStreamSSLLevel
- * - kCFStreamSSLAllowsExpiredCertificates
- * - kCFStreamSSLAllowsExpiredRoots
- * - kCFStreamSSLAllowsAnyRoot
- * - kCFStreamSSLValidatesCertificateChain
- * - kCFStreamSSLPeerName
- * - kCFStreamSSLCertificates
- * - kCFStreamSSLIsServer
- 如果你传递空或者空字典,将使用默认的字典
- 默认设置将检查以确保由签署可信的第三方证书机构和没有过期的远程连接的证书
- 然而,它不会验证证书上的名字,除非你给它一个名字,通过kCFStreamSSLPeerName键去验证
- 这对安全的影响是重要的理解
- 想象一下你正试图创建一个到MySecureServer.com的安全连接,但因为一个被攻击的DNS服务器,所以你的socket被定向到MaliciousServer.com
- 如果你只是使用默认设置,MaliciousServer.com 有一个有效的证书
- 默认设置将无法监测到任何问题,因为证书是有效的
- 在这个特殊的情况下,要妥善保护你的连接,应设置kCFStreamSSLPeerName性质为MySecureServer.com.
- 如果事前你不知道对等的名字的远程主机(例如,你不确认它是domain.com" or "www.domain.com"),那么你可以使用默认设置来验证证书,然后在获得验证的发行后使用X509Certificate类来验证,X509Certificate类的CocoaAsyncSocket开源项目的一部分
- -(void)enablePrebuffering
- 对于处理readDataToData请求,数据是必须从socket以小增量的方式读取出来的
- 性能通过允许AsyncSocket去一次性读大块的数据和存储任何一个小的内部缓冲区溢出的东西来大大提高
- 这被称为预缓冲,就好像一些数据在你要求它之前就可能被读取出来
- 如果你经常使用readDataToData,使用预缓冲会有更好的性能,尤其是在iphone上
- 默认的预缓冲状态是由DEFAULT_PREBUFFERING 定义控制的,强烈建议设置其为yes
- 这方法存在一些预缓冲需要一些不可预见的原因被默认禁用的情况,这时,这种方法存在允许当就绪时,可轻松启用预缓冲
- -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop;
- 当你创建一个AsyncSocket,它被添加到当前线程runloop
- 对于手动创建的socket,在线程上你打算使用它,它是最容易简单的创建的线程上的socket
- 当一个新的socket被接受,委托方法 onSocket:wantsRunLoopForNewSocket 会被调用 允许你在一个单独的线程上放置socket,这个工作最好结合在同一个线程池设计
- 如果,但是,在一个单独的线程上,在之后的时间,你需要移动一个socket,这个方法可以用来完成任务
- 此方法必须从 当前运行的 线程/runloop 的socket 调用
- 注意:此方法调用后,所有进一步的方法应该从给定的runloop上调用这个对象
- 此外,所有委托调用将会发送到给定的runloop
- - (BOOL)setRunLoopModes:(NSArray *)runLoopModes;
- - (BOOL)addRunLoopMode:(NSString *)runLoopMode;
- - (BOOL)removeRunLoopMode:(NSString *)runLoopMode;
- 允许你配置 socket 使用的 运行循环模式
- 运行循环模式设置默认是NSRunLoopCommonModes
- 如果你想你的socket 在其他模式下继续操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes
- 可接受的socket将自动 继承相同的运行循环模式就像侦听socket
- 注意:NSRunLoopCommonModes 定义在10.5,对于之前的版本可使用 kCFRunLoopCommonModes
- -(NSArray *)runLoopModes
- 返回当前正在运行的循环模式的AsyncSocket实例, run loop modes的默认设置是NSDefaultRunLoopMode
- -(NSData *)unreadData;
- 一个错误的事件,在 onSocket:willDisconnectWithError: 将会被调用 去读取留在socket上的任何数据
- + (NSData *)CRLFData; // 0x0D0A
【IOS网络编程】socket编程 - Asyncsocket的更多相关文章
- python网络编程-socket编程
一.服务端和客户端 BS架构 (腾讯通软件:server+client) CS架构 (web网站) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 二.OSI七层 ...
- Day8 - Python网络编程 Socket编程
Python之路,Day8 - Socket编程进阶 本节内容: Socket语法及相关 SocketServer实现多并发 Socket语法及相关 socket概念 socket本质上就是在2台 ...
- 网络编程——socket编程
一.客户端/服务端架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网企业处处是C/S架构 C/S架构与socket的关系:学习socket就是为了完成C/S架构的开发 二.OSI七层 一个 ...
- Day10 Python网络编程 Socket编程
一.客户端/服务器架构 1.C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架构(web服务)[QQ,SSH,MySQL,FTP] 2.C/S架构与socket的关系: 我们学习soc ...
- Python的网络编程 Socket编程
Socket是进程间通信的一种方式,与其他进程间通信的一个主要不同是:能实现不同主机间的进程间通信,网络上各种各样的服务大多都是基于Socket来完成通信的,要解决网络上两台主机间的通信问题,首先要唯 ...
- HUST-计算机网络实验-socket编程
随笔---HUST计网实验:socket编程 博主大三在读,第一次写随笔,水平有限,就当记录一下学习的过程,顺便面试前复习项目的时候看看. 实验要求: 编写一个 Web 服务器软件,要求如下: 基本要 ...
- iOS开发网络篇—Socket编程
一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程 ...
- 网络编程 socket编程 - Asyncsocke
简单的聊天程序:http://blog.csdn.net/chang6520/article/details/7967662 iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 c ...
- python网络编程socket编程(TCP、UDP客户端服务器)
摘录 python核心编程 使用socket()模块函数创建套接字——通信端点 >>> from socket import * >>> tcpSock = soc ...
- 网络编程----------SOCKET编程实现简单的TCP协议
首先我们须要大致了解TCP的几点知识: 1.TCP的特点:面向连接的可靠性传输 2.TCP的三次握手建立连接和四次挥手释放连接.但为什么TCP要三次握手建立连接呢? 答:由于两次握手无法保证可靠性.若 ...
随机推荐
- Thunderbird and Gmail
https://support.mozilla.org/en-US/kb/thunderbird-and-gmail
- 匹配 C 语言样式字符串
#include <stdio.h> char haha[] = "nihaoma" "niubi" "\"hello worl ...
- 08.C语言:特殊函数
C语言:特殊函数 1.递归函数: 与普通函数比较,执行过程不同,该函数内部调用它自己,它的执行必须要经过两个阶段:递推阶段,回归阶段: 当不满足回归条件,不再递推: #include <stdi ...
- String HDU 5672(双指针)
String HDU 5672(双指针) 传送门 题意:一个字符串中找到所有拥有不少于k个不同的字符的子串. import java.io.*; import java.util.*; public ...
- 3.2.1.1 POSIX方括号表达式
为配合非英语的环境,POSIX 标准强化其字符集范围的能力(例如,[a-z]),以匹配非英文字母字符. POSIX 也在一般术语上作了些变动,我们早先看到的范围表达式在 UNIX ...
- 百练2755:神奇的口袋(简单dp)
描述有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40.John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an.John可以从这些物品中选择一些 ...
- Leetcode 80.删除重复数组的重复项
删除重复数组的重复项 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间 ...
- 初次使用Let's encrypt
wget --no-check-certificate -O shadowsocks.sh https://raw.githubusercontent.com/teddysun/shadowsocks ...
- [bzoj5301][Cqoi2018]异或序列_莫队
异或序列 bzoj-5301 Cqoi-2018 题目大意:题目链接. 注释:略. 想法: 由于a^a=0这个性质,我们将所有的数变成异或前缀和. 所求就变成了求所有的$l_i\le x<y\l ...
- 武大OJ 622. Symmetrical
Description Cyy likes something symmetrical, and Han Move likes something circular. Han Mov ...