[转]: 用GCDAsyncSocket解决AsyncSocket读取数据时丢失部分消息

时间:2024-02-21 20:51:06

原文地址:http://blog.csdn.net/cdy2143/article/details/8963422

在项目中,一直都是用AsyncSocket的开源项目来做IOS的Socket的开发,现在遇到一个问题:当数据包比较频繁的发送到手机时,即使使用了readDataToData,还是会出现丢包的问题且读到的包中还会出现分割符。后面终于参考了其他的文章,看到GCDAsyncSocket,结果试了一把,readDataToData,能正常分割数据,即按行来分,且不丢包了。

使用GCDAsyncSocket的方法如下:

1、https://github.com/robbiehanson/CocoaAsyncSocket,从这个地址,将GCD目录下的GCDAsyncSocket.h和GCDAsyncSocket.m文件下载下来,添加到你的项目中,然后,在引入CFNetwork.framework和Security.framework,如下图:

2、使用代码

 

[plain] view plaincopy
 
//建立连接  
-(NSError *)setupConnection {  
    if (nil == socket)  
        socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];  
    NSError *err = nil;  
    NSLog(@"IP: %@, port:%i",hostAddress,hostPort);  
    if (![socket connectToHost:hostAddress  onPort:hostPort error:&err]) {  
        NSLog(@"Connection error : %@",err);  
    } else {  
        err = nil;  
    }  
    needConnect = YES;  
    return err;  
}  
  
//判断是否是连接的状态  
-(BOOL)isConnected {  
    return socket.isConnected;  
}  
  
//断开连接  
-(void)disConnect {  
    needConnect = NO;  
    [socket disconnect];  
}  
  
//取得连接  
-(void)getConnection {  
    if (![socket isConnected]) {  
        [self disConnect];  
        //        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(setupConnection) userInfo:nil repeats:NO];  
        //        NSLog(@"scheduled start");  
        [self setupConnection];  
    }  
}  
  
-(void)sendCMD {  
    [self getConnection];  
//    NSString* cmd = [[NSString alloc] init];  
//    cmd = [cmd stringByAppendingString:@"BBBB1,zzc,202cb962ac59075b964b07152d234b70,201304182033EEEE"];  
    NSString* cmd = @"BBBB1,zzc,202cb962ac59075b964b07152d234b70,201304182033EEEE\n";  
    NSData *data = [cmd dataUsingEncoding:NSUTF8StringEncoding];  
    [socket writeData:data withTimeout:20 tag:1];  
}  
  
//socket连接成功后的回调代理  
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {  
    NSLog(@"onSocket:%p didConnectToHost:%@ port:%hu", sock, host, port);  
    [delegate networkConnected];  
    [self listenData];  
}  
  
//socket连接断开后的回调代理  
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {  
    NSLog(@"DisConnetion");  
    [socket disconnect];  
    [delegate networkDisconnect];  
    //    if (needConnect)  
    //        [self getConnection];  
}  
  
//读到数据后的回调代理  
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {  
    NSLog(@"receive datas from method 1");  
    //    NSLog(@"Data length = %d",[data length]);  
    [self listenData];  
    [delegate readData:data];  
//    [self splitData:data];  
    //    [self listenData];  
}  
  
-(void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {  
     NSLog(@"Reading data length of %d",partialLength);  
}  
  
//发起一个读取的请求,当收到数据时后面的didReadData才能被回调  
-(void)listenData {  
//    NSString* sp = @"\n";  
//    NSData* sp_data = [sp dataUsingEncoding:NSUTF8StringEncoding];  
    [socket readDataToData:[GCDAsyncSocket LFData] withTimeout:-1 tag:1];  
//    [socket readDataWithTimeout:-1 tag:1];  
}  

 

3、付上从网络上取得到数据包后,自己用分割符来分割数据,如用换行符号分割数据包

 

 

[plain] view plaincopy
 
<p class="p1">NSMutableData<span style="font-family: Arial, Helvetica, sans-serif;">* restData;</span></p>//分割数据包  
-(void)splitData:(NSData*)orignal_data {  
    NSUInteger l = [orignal_data length];  
    NSLog(@"Data length1 = %d",l);  
    NSString* sp = @"\n";  
    NSData* sp_data = [sp dataUsingEncoding:NSUTF8StringEncoding];  
    NSUInteger sp_length = [sp_data length];  
    NSUInteger offset = 0;  
    int line = 0;  
    while (TRUE) {  
        NSUInteger index = [self indexOfData:sp_data inData:orignal_data offset:offset];  
        if (NSNotFound == index) {  
            if (offset<l) {  
                NSLog(@"Have data not read");  
                NSRange range = {offset,l-offset};  
                NSData* rest = [orignal_data subdataWithRange:range];  
                if (restData == nil) {  
                    restData = [[NSMutableData alloc] init];  
                }  
                [restData appendData:rest];  
            }  
            return;  
        }  
        NSUInteger length = index + sp_length;  
        NSRange range = {offset,length-offset};  
        NSData* sub = [orignal_data subdataWithRange:range];  
        if (restData != nil) {  
            [restData appendData:sub];  
            [delegate readData:restData];  
            restData = nil;  
        } else {  
            NSLog(@"line %d",line++);  
            [delegate readData:sub];  
        }  
        offset += length;  
    }  
}  
  
//查找指定的数据包的位置  
- (NSUInteger)indexOfData:(NSData*)needle inData:(NSData*)haystack offset:(NSUInteger)offset  
{  
    Byte* needleBytes = (Byte*)[needle bytes];  
    Byte* haystackBytes = (Byte*)[haystack bytes];  
      
    // walk the length of the buffer, looking for a byte that matches the start  
    // of the pattern; we can skip (|needle|-1) bytes at the end, since we can\'t  
    // have a match that\'s shorter than needle itself  
    for (NSUInteger i=offset; i < [haystack length]-[needle length]+1; i++)  
    {  
        // walk needle\'s bytes while they still match the bytes of haystack  
        // starting at i; if we walk off the end of needle, we found a match  
        NSUInteger j=0;  
        while (j < [needle length] && needleBytes[j] == haystackBytes[i+j])  
        {  
            j++;  
        }  
        if (j == [needle length])  
        {  
            return i;  
        }  
    }  
    return NSNotFound;  
}