http 和socket
来源:互联网 发布:革命之路 知乎 编辑:程序博客网 时间:2024/05/13 20:32
http编程综述:亦可称为soap编程。通常情况下,http编程要比socket编程相对要简单易用得多。所以用的最广广泛。
一、http编程其实就是http请求。http请求最长用的方法是 get 和 post 方法。
==》get方法和post方法相比理解起来比较简单,get方法可以直接请求一个url,也可以url后面拼接上参数作为一个新的url地址进行请求。get方法后面的value要经过unicode编码。form的enctype属性默认为application/x-www-form-urlencoded。不能发送二进制文件。
==》post方法相对要复杂一些。首先post方法要设置key和value ,所有的key和value都会拼接成 key1=value1&key2=value2的样式的字符串,然后这个字符串转化为二进制放到 http请求的body中。当请求发送的时候,也就跟随body一起传给服务器。http请求Content-Type设置为:application/x-www-form-urlencoded。这里讲的只是简单的post请求,一般发送文件不会选择这种方式(从技术方面考虑也可以发送文件,就是把文件以 key 和 value的方式放入)。下面我们再讨论一下post发送二进制文件更加普遍的方法。
==》post方法相对要复杂一些。首先post方法要设置key和value ,所有的key和value都会拼接成 key1=value1&key2=value2的样式的字符串,然后这个字符串转化为二进制放到 http请求的body中。当请求发送的时候,也就跟随body一起传给服务器。http请求Content-Type设置为:application/x-www-form-urlencoded。这里讲的只是简单的post请求,一般发送文件不会选择这种方式(从技术方面考虑也可以发送文件,就是把文件以 key 和 value的方式放入)。下面我们再讨论一下post发送二进制文件更加普遍的方法。
二、HTTP协议是什么?
简单来说,就是一个基于应用层的通信规范:双方要进行通信,大家都要遵守一个规范,这个规范就是HTTP协议。
HTTP协议能做什么?
很多人首先一定会想到:浏览网页。没错,浏览网页是HTTP的主要应用,但是这并不代表HTTP就只能应用于网页的浏览。HTTP是一种协议,只要通信的双方都遵守这个协议,HTTP就能有用武之地。比如咱们常用的QQ,迅雷这些软件,都会使用HTTP协议(还包括其他的协议)。
HTTP协议如何工作?
大家都知道一般的通信流程:首先客户端发送一个请求(request)给服务器,服务器在接收到这个请求后将生成一个响应(response)返回给客户端。
在这个通信的过程中HTTP协议在以下4个方面做了规定:
简单来说,就是一个基于应用层的通信规范:双方要进行通信,大家都要遵守一个规范,这个规范就是HTTP协议。
HTTP协议能做什么?
很多人首先一定会想到:浏览网页。没错,浏览网页是HTTP的主要应用,但是这并不代表HTTP就只能应用于网页的浏览。HTTP是一种协议,只要通信的双方都遵守这个协议,HTTP就能有用武之地。比如咱们常用的QQ,迅雷这些软件,都会使用HTTP协议(还包括其他的协议)。
HTTP协议如何工作?
大家都知道一般的通信流程:首先客户端发送一个请求(request)给服务器,服务器在接收到这个请求后将生成一个响应(response)返回给客户端。
在这个通信的过程中HTTP协议在以下4个方面做了规定:
1. Request和Response的格式()
2. 建立连接的方式(1、非持久连接 2、持久连接)
3. 缓存的机制
4. 响应授权激发机制
2. 建立连接的方式(1、非持久连接 2、持久连接)
3. 缓存的机制
4. 响应授权激发机制
(应用场合)
5. 基于HTTP的应用(1、 HTTP代理 2、多线程下载 3、 HTTPS传输协议原理 4、开发web程序时常用的Request Methods 5、用户与服务器的交互)
5. 基于HTTP的应用(1、 HTTP代理 2、多线程下载 3、 HTTPS传输协议原理 4、开发web程序时常用的Request Methods 5、用户与服务器的交互)
常用cocoa内部类:
1,Reachability.h 苹果demo支持网络连接诊断
2,NSConnection连接、NSMutableURLRequest URL网址的请求封装包
3,NSXMLParser XML解析
常用第三方库:
1,ASIHttprequest 库
操作步骤:
1:检查网络环境(3G/WIFI)
2:发起NSConnection请求
3:处理返回xml数据包(NSXMLParser解析xml文件),或者返回文件png、pdf之类
4:若返回数据包中含有待下载的图片下载地址。则重复2、3步骤下载下来图片。只不过3中返回的是文件。
socket编程综述:
2:发起NSConnection请求
3:处理返回xml数据包(NSXMLParser解析xml文件),或者返回文件png、pdf之类
4:若返回数据包中含有待下载的图片下载地址。则重复2、3步骤下载下来图片。只不过3中返回的是文件。
socket编程综述:
常用cocoa内部类:
常用第三方库:1,Asyncsocket库
操作步骤:
- iPhone的标准推荐是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如果不为空的话,它们将会被填补
http网络编程实例
一:确认网络环境3G/WIFI1. 添加源文件和framework
开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息。如果没有处理它们,是不会通过Apple的审查的。
Apple 的 例程 Reachability 中介绍了取得/检测网络状态的方法。要在应用程序程序中使用Reachability,首先要完成如下两部:
1.1. 添加源文件:
在你的程序中使用 Reachability 只须将该例程中的 Reachability.h 和 Reachability.m 拷贝到你的工程中。如下图:
1.2.添加framework:
将SystemConfiguration.framework 添加进工程。如下图:
2. 网络状态
Reachability.h中定义了三种网络状态:
typedef enum {
NotReachable = 0, //无连接
ReachableViaWiFi, //使用3G/GPRS网络
ReachableViaWWAN //使用WiFi网络
} NetworkStatus;
因此可以这样检查网络状态:
Reachability *r = [Reachability reachabilityWithHostName:@“www.apple.com”];
switch ([r currentReachabilityStatus]) {
case NotReachable:
// 没有网络连接
break;
case ReachableViaWWAN:
// 使用3G网络
break;
case ReachableViaWiFi:
// 使用WiFi网络
break;
}
3.检查当前网络环境
程序启动时,如果想检测可用的网络环境,可以像这样
// 是否wifi
+ (BOOL) IsEnableWIFI {
return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable);
}
// 是否3G
+ (BOOL) IsEnable3G {
return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable);
}
例子:
- (void)viewWillAppear:(BOOL)animated {
if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) &&
([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) {
self.navigationItem.hidesBackButton = YES;
[self.navigationItem setLeftBarButtonItem:nil animated:NO];
}
}
4. 链接状态的实时通知
网络连接状态的实时检查,通知在网络应用中也是十分必要的。接续状态发生变化时,需要及时地通知用户:
Reachability 1.5版本
// My.AppDelegate.h
#import "Reachability.h"
@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
NetworkStatus remoteHostStatus;
}
@property NetworkStatus remoteHostStatus;
@end
// My.AppDelegate.m
#import "MyAppDelegate.h"
@implementation MyAppDelegate
@synthesize remoteHostStatus;
// 更新网络状态
- (void)updateStatus {
self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus];
}
// 通知网络状态
- (void)reachabilityChanged:(NSNotification *)note {
[self updateStatus];
if (self.remoteHostStatus == NotReachable) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil)
message:NSLocalizedString (@"NotReachable", nil)
delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
// 程序启动器,启动网络监视
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// 设置网络检测的站点
[[Reachability sharedReachability] setHostName:@"www.apple.com"];
[[Reachability sharedReachability] setNetworkStatusNotificati*****Enabled:YES];
// 设置网络状态变化时的通知函数
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:)
name:@"kNetworkReachabilityChangedNotification" object:nil];
[self updateStatus];
}
- (void)dealloc {
// 删除通知对象
[[NSNotificationCenter defaultCenter] removeObserver:self];
[window release];
[super dealloc];
}
Reachability 2.0版本
// MyAppDelegate.h
@class Reachability;
@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
Reachability *hostReach;
}
@end
// MyAppDelegate.m
- (void)reachabilityChanged:(NSNotification *)note {
Reachability* curReach = [note object];
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
NetworkStatus status = [curReach currentReachabilityStatus];
if (status == NotReachable) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AppName""
message:@"NotReachable"
delegate:nil
cancelButtonTitle:@"YES" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// ...
// 监测网络情况
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reachabilityChanged:)
name: kReachabilityChangedNotification
object: nil];
hostReach = [[Reachability reachabilityWithHostName:@"www.google.com"] retain];
hostReach startNotifer];
// ...
}
二:使用NSConnection下载数据
1.创建NSConnection对象,设置委托对象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]]];
[NSURLConnection connectionWithRequest:request delegate:self];
2. NSURLConnection delegate委托方法
- (void)connection:(NSURLConnection *)connection didReceiveResp*****e:(NSURLResp*****e *)resp*****e;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
3. 实现委托方法
- (void)connection:(NSURLConnection *)connection didReceiveResp*****e:(NSURLResp*****e *)resp*****e {
// store data
[self.receivedData setLength:0]; //通常在这里先清空接受数据的缓存
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
/* appends the new data to the received data */
[self.receivedData appendData:data]; //可能多次收到数据,把新的数据添加在现有数据最后
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// 错误处理
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// disconnect
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSString *returnString = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSLog(returnString);
[self urlLoaded:[self urlString] data:self.receivedData];
firstTimeDownloaded = YES;
}
三:使用NSXMLParser解析xml文件
1. 设置委托对象,开始解析
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //或者也可以使用initWithContentsOfURL直接下载文件,但是有一个原因不这么做:
// It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable
// because it gives less control over the network, particularly in responding to connection errors.
[parser setDelegate:self];
[parser parse];
2. 常用的委托方法
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError;
static NSString *feedURLString = @"http://www.yifeiyang.net/test/test.xml";
3. 应用举例
- (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
NSError *parseError = [parser parserError];
if (parseError && error) {
*error = parseError;
}
[parser release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString*)qName attributes:(NSDictionary *)attributeDict{
// 元素开始句柄
if (qName) {
elementName = qName;
}
if ([elementName isEqualToString:@"user"]) {
// 输出属性值
NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
// 元素终了句柄
if (qName) {
elementName = qName;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// 取得元素的text
}
NSError *parseError = nil;
[self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError];
//实例
//
// NLViewController.m
// NetWorkTest
//
// Created by Nono on 12-5-16.
// Copyright (c) 2012年 NonoWithLilith. All rights reserved.
//
#import "NLViewController.h"
@interface NLViewController ()
@end
@implementation NLViewController
@synthesize label = _label;
@synthesize data = _data;
@synthesize connection = _connection;
- (void)dealloc{
[self.label release];
[self.data release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 10.0, 300.0, 400)];
self.label = label;
label.textAlignment = UITextAlignmentCenter;
[label setNumberOfLines:0];
label.lineBreakMode = UILineBreakModeWordWrap;
self.label.text = @"正在在请求数据";
[self.view addSubview:label];
[label release];
//step 1:请求地址
NSString *urlString = @"http://www.google.com";
NSURL *url = [NSURL URLWithString:urlString];
//step 2:实例化一个request
NSURLRequest *requrst = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
//step 3:创建链接
self.connection = [[NSURLConnection alloc] initWithRequest:requrst delegate:self];
if ( self.connection) {
NSLog(@"链接成功");
}else {
NSLog(@"链接失败");
}
[url release];
[urlString release];
[requrst release];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
self.label = nil;
self.data = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark-
#pragma NSUrlConnectionDelegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//接受一个服务端回话,再次一般初始化接受数据的对象
NSLog(@"返回数据类型:%@",[response textEncodingName]);
NSMutableData *d = [[NSMutableData alloc] init];
self.data = d;
[d release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//接受返回数据,这个方法可能会被调用多次,因此将多次返回数据加起来
NSUInteger datalength = [data length];
NSLog(@"返回数据量:%d",datalength);
[self.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//连接结束
NSLog(@"%d:",[self.data length]);
NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *mystr = [[NSString alloc] initWithData:_data encoding:enc];
// string i
NSLog(@"最后的结果:%@",mystr);
self.label.text = mystr;
[mystr release];
[self.connection release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//链接错误
}
@end
0 0
- HTTP---Http和Socket区别
- Http和socket
- Socket和Http通信
- http和socket
- HTTP和SOCKET 区别
- Http和Socket入门
- HTTP和Socket
- HTTP和Socket
- Socket和Http通信
- Http和Socket区别
- Http和Socket区别
- HTTP和Socket
- Http和Socket区别
- HTTP和Socket
- http和socket
- Socket 和 HTTP 协议
- http和socket
- Http和Socket区别
- HDOJ-1686 Oulipo ---KMP
- JSP生命周期
- Java开发常见问题之 - java.lang.OutOfMemoryError:PermGen space
- Google AdMob 广告 iOS 初级指南
- Servlet 3.0 实战:异步 Servlet 与 Comet 风格应用程序
- http 和socket
- base关键字
- Caché获取对象
- shell中括号的作用
- PHP相关系列 - 商品秒杀库存问题
- minpack.cpp
- 参加某培训机构Java培训记录(十)
- 块语法Block在MVC思维的妙用之多重M层代理传值
- J2EE 登录验证