在项目中,一直都是用AsyncSocket的开源项目来做IOS的Socket的开发,现在遇到一个问题:当数据包比较频繁的发送到手机时,即使使用了readDataToData,还是会出现丢包的问题且读到的包中还会出现分割符。后面终于参考了其他的文章,看到GCDAsyncSocket,结果试了一把,readDataToData,能正常分割数据,即按行来分,且不丢包了。
使用GCDAsyncSocket的方法如下:
1、https://github.com/robbiehanson/CocoaAsyncSocket,从这个地址,将GCD目录下的GCDAsyncSocket.h和GCDAsyncSocket.m文件下载下来,添加到你的项目中,然后,在引入CFNetwork.framework和Security.framework,如下图:
2、使用代码
//建立连接
-(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、付上从网络上取得到数据包后,自己用分割符来分割数据,如用换行符号分割数据包
NSMutableData* restData;
//分割数据包
-(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;
}