AsyncSocket didReadData函数详解

来源:互联网 发布:流量控制软件电脑 编辑:程序博客网 时间:2024/05/16 16:23

恐怕在AsyncSocket框架中,最关键的一个函数要数

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;

这个函数在socket输入流获取到数据时被调用,也可以自定义timeout和length。本文重点讨论这个基本函数使用中容易出现的问题。如果socket使用没有问题,基本上读取到数据没有问题,但是如果服务器发送了多个socket请求,导致didReadData函数被反复调用,并且不知道什么时候是最后一次请求。

因为服务器端和客户端对socket的处理不一样,所以先来看看在客户端,didReadData函数的用法。
首先要在方法的最后设置读取数据超时时间。

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{    //…………    //前面是各种处理    [client readDataWithTimeout:-1 tag:0];}

这样,socket会不断获取数据,直到数据被完全获取为止。
但是,程序员怎么知道数据已经全部被获取到了呢?我们需要另外添加一个变量来实现这个功能。

@property (nonatomic, retain) NSMutableData *receiveData;

我们定义了一个NSMutableData类型的data,然后每次获取到数据的时候,就把获取到的数据附加到receiveData上,并且判断数据是否已经读取完成。因此,我们把didReadData修改如下:

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{    if (receiveData == nil) {        //如果不存在,则创建一个新的        receiveData = [[NSMutableData alloc] init];    }    [receiveData appendData:data];//把接收到的数据添加上    NSRange endRange = [aStr rangeOfString:@"\r"];    if (endRange.location != NSNotFound) {        //这里表示数据已经读取完成了        //在if代码块中处理receiveData        receiveData = nil;//用于接受数据的对象置空    }    //别忘了设置timeout    [client readDataWithTimeout:-1 tag:0];}

注意这一行代码

NSRange endRange = [aStr rangeOfString:@"\r"];

服务器在发送socket数据时,在结束的时候一定都会有一个标记,这里我请求的服务器的结束标记就是\r,不同的服务器可能有不同的标记,但往往不外乎\r、\0、\n之类的,可以自己尝试一下。
endRange表示\r的出现位置,如果\r出现了,就表示数据已经完成读取,可以处理了,如果\r不出现,didReadData函数会一直执行,知道数据完全被获取到。

此外,除了结束符标记法之外,我们还可以根据content-length来判断。第一次获取数据,即使不完整,但是返回报文头的content-length还是可以获取到的,以后以后每次获取数据,就判断长度是否已经达到。不过这种方法需要找到返回的数据内容并计算data长度,比较繁琐,可以作为备用方法,这里就不实现了。

至于服务器端,也存在这样的问题。不过服务器端的设置比较简单。didReadData的修改类似于客户端。至于timeout,我们可以不在didReadData方法中设置,因为这样的设置会导致第一次总是会拿到数据。我们可以放在didReadData函数被调用之前就设置。如:

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{     //…………    //前面是各种处理    [sock readDataWithTimeout:-1 tag:0];}
0 0