码迷,mamicode.com
首页 > 其他好文 > 详细

总结一下前两天刚尝试的socket编程-使用AsyncSocket

时间:2014-08-16 12:26:10      阅读:547      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   java   使用   os   io   

说来惭愧,搞了两年ios居然木有用过socket...初学ios的时候倒是了解过,但是两年不用,之前学的内容已经完全忘光光.于是又开始网上各种查.

用cf的socket貌似显得很拽的样子,但是实在不适合我这种领导紧逼着出项目的情况.搜了下发现目前最常用的socket库应该就是AsyncSocket了.嗯,看起来很简单,搞it~

这个库有基于runloop和GCD两种,据我一哥们说runloop版本是基于timer机制实现异步处理,会跟scroller的滚动动画冲突.我暂时还没有验证他的说法,不过保险起见还是用了GCD.因为服务端那里用的是tcp,所以最终我只导入了GCDAsyncSocket.h/.m两个文件.

socket的数据处理放在一个JLYSocketManager类进行.因为我们是程序在就一直保持长链,所以直接搞成单例.

以下正题:

首先要进行连接:

 1     if (!_asynSocket)
 2     {
 3         _asynSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
 4     }
 5     
 6     NSError *err = nil;
 7     if(![_asynSocket connectToHost:kSocketHost onPort:kSocketPort error:&err])
 8     {
 9         //handle error
10         NSLog(@"Error: %@", err);
11         _retryTime++;
12         [self connentServer];
13     }
14     else
15     {
16         //do sth after connect
17     }

 

成功连接之后就可以推数据或者读服务器的数据了.

1 //get data from server
2 [_asynSocket readDataWithTimeout:-1 tag:0];
3 
4 //send data to server
5 [_asynSocket writeData:data withTimeout:-1 tag:0];

 

然后要设置一些相应的委托方法,我主要用了下面几个:

1 #pragma mark -
2 #pragma mark -----socket delegate-----
3 - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
4 
5 - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
6 
7 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
8 
9 - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;

不用多说,看名字就能明白这几个方法是干嘛的.

值得注意的是,你需要在"适当的地方"设置数据读取的监听,其实就是调用上面说的readDataWithTimeout方法.比如在didConnectToHost里,接收建立信道后服务端传来的链接状态信息.或者接受了一次数据,然后在didReadData里面设置继续监听.总之就是你需要保持一致向服务端索取数据.

so easy吧~

tcp通信必然伴随着粘包或者拆包的情况.而每次通过didReadData这个委托方法收到的是数据都是以包为单位.拆包粘包说白了就是服务器一次给你发了很多条信息,但是这些信息不是一条信息一个包,而是一条信息分了几个包发来,或者几条信息的数据合到一个包发来了.

java貌似自己有框架,闭着眼就能完成拆包合包的工作.但是oc上貌似没找到.只好手动.那首先要跟服务器有个协议,说明一下以什么作为一条信息的节点.比如我们,每条信息的头四个字节是用来保存这条信息的应有长度的.接到信息首先要读取长度,然后再跟收到的数据包长度对比.如果收到的长度刚刚好,说明这是一条完整的信息,直接封起来就行.如果收到的长度比预计长度短,说明信息被拆包发送,那就要继续跟下一个包进行拼装,再检验长度.如果收到的长度比预计的长,说明发生了粘包,那就要根据预计长度对数据包的数据进行拆分,对拆出的两部分数据继续进行处理.

说起来很啰嗦,其实简单,大概就是这么个方法:

bubuko.com,布布扣
 1 /**
 2  *  处理_bufferData
 3  *  主要处理拆包粘包问题.获得每段数据的长度之后,和当前buffer比较,如果刚好说明接收完全;如果buffer过大说明服务端粘包,需要拆包;如果buffer小说明服务端拆包,需要合包
 4  *
 5  *  @param newData 获取的新数据,如果只是本地拆包则传nil
 6  */
 7 - (void)handleBufferData:(NSData *)newData
 8 {
 9     if (newData)
10     {
11         //这是一个缓冲区,因为是全局的,并且是单例中,所以在数据取走的时候一定要清空
12         [_bufferData appendData:newData];
13     }
14     
15     //首先取前四位
16     int i = 0;
17     [_bufferData getBytes:&i range:NSMakeRange(0, 4)];
18     //因为oc和java字节数组的高地位顺序是反的,所以要翻转一下顺序
19     Byte *fix = [self overturnIntByteArr:i];
20     memcpy(&i, fix, 4);
21     free(fix);
22 
23     //刚好
24     if (i == [_bufferData length]-4)
25     {
26         NSData *contentData = [_bufferData subdataWithRange:NSMakeRange(4, i)];
27         //完整接收了一条信息的处理
28         [self finishGetWholeData:contentData];
29         
30         _bufferData = [NSMutableData data];
31     }
32     //需要拆包
33     else if (i < [_bufferData length]-4)
34     {
35         NSData *contentData = [_bufferData subdataWithRange:NSMakeRange(4, i)];
36         //这是完成了第一个包的数据的接收
37         [self finishGetWholeData:contentData];
38         
39         NSData *buffer = [_bufferData subdataWithRange:NSMakeRange(i+4, _bufferData.length-i-4)];
40         _bufferData = [NSMutableData data];
41         [_bufferData appendData:buffer];
42         
43         //继续进行判断处理
44         [self handleBufferData:nil];
45     }
46 }
47     
View Code

大概就是酱紫.思路是这样,但是估摸着是会有一些问题的,以后使用中再慢慢完善吧~

 

总结一下前两天刚尝试的socket编程-使用AsyncSocket,布布扣,bubuko.com

总结一下前两天刚尝试的socket编程-使用AsyncSocket

标签:style   blog   http   color   java   使用   os   io   

原文地址:http://www.cnblogs.com/forhonour/p/3916191.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!