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