如何使用 GCDASyncSocket 时分隔数据访问ip地址时的数据包包

总结一下前两天刚尝试的socket编程-使用AsyncSocket
时间: 12:26:10
&&&& 阅读:6271
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&说来惭愧,搞了两年ios居然木有用过socket...初学ios的时候倒是了解过,但是两年不用,之前学的内容已经完全忘光光.于是又开始网上各种查.
用cf的socket貌似显得很拽的样子,但是实在不适合我这种领导紧逼着出项目的情况.搜了下发现目前最常用的socket库应该就是AsyncSocket了.嗯,看起来很简单,搞it~
这个库有基于runloop和GCD两种,据我一哥们说runloop版本是基于timer机制实现异步处理,会跟scroller的滚动动画冲突.我暂时还没有验证他的说法,不过保险起见还是用了GCD.因为服务端那里用的是tcp,所以最终我只导入了GCDAsyncSocket.h/.m两个文件.
socket的数据处理放在一个JLYSocketManager类进行.因为我们是程序在就一直保持长链,所以直接搞成单例.
首先要进行连接:
if (!_asynSocket)
_asynSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *err =
if(![_asynSocket connectToHost:kSocketHost onPort:kSocketPort error:&err])
//handle error
NSLog(@"Error: %@", err);
_retryTime++;
[self connentServer];
//do sth after connect
成功连接之后就可以推数据或者读服务器的数据了.
1 //get data from server
2 [_asynSocket readDataWithTimeout:-1 tag:0];
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)
5 - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)
7 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)
9 - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)
不用多说,看名字就能明白这几个方法是干嘛的.
值得注意的是,你需要在"适当的地方"设置数据读取的监听,其实就是调用上面说的readDataWithTimeout方法.比如在didConnectToHost里,接收建立信道后服务端传来的链接状态信息.或者接受了一次数据,然后在didReadData里面设置继续监听.总之就是你需要保持一致向服务端索取数据.
so easy吧~
tcp通信必然伴随着粘包或者拆包的情况.而每次通过didReadData这个委托方法收到的是数据都是以包为单位.拆包粘包说白了就是服务器一次给你发了很多条信息,但是这些信息不是一条信息一个包,而是一条信息分了几个包发来,或者几条信息的数据合到一个包发来了.
java貌似自己有框架,闭着眼就能完成拆包合包的工作.但是oc上貌似没找到.只好手动.那首先要跟服务器有个协议,说明一下以什么作为一条信息的节点.比如我们,每条信息的头四个字节是用来保存这条信息的应有长度的.接到信息首先要读取长度,然后再跟收到的数据包长度对比.如果收到的长度刚刚好,说明这是一条完整的信息,直接封起来就行.如果收到的长度比预计长度短,说明信息被拆包发送,那就要继续跟下一个包进行拼装,再检验长度.如果收到的长度比预计的长,说明发生了粘包,那就要根据预计长度对数据包的数据进行拆分,对拆出的两部分数据继续进行处理.
说起来很啰嗦,其实简单,大概就是这么个方法:
处理_bufferData
主要处理拆包粘包问题.获得每段数据的长度之后,和当前buffer比较,如果刚好说明接收完全;如果buffer过大说明服务端粘包,需要拆包;如果buffer小说明服务端拆包,需要合包
@param newData 获取的新数据,如果只是本地拆包则传nil
7 - (void)handleBufferData:(NSData *)newData
if (newData)
//这是一个缓冲区,因为是全局的,并且是单例中,所以在数据取走的时候一定要清空
[_bufferData appendData:newData];
//首先取前四位
int i = 0;
[_bufferData getBytes:&i range:NSMakeRange(0, 4)];
//因为oc和java字节数组的高地位顺序是反的,所以要翻转一下顺序
Byte *fix = [self overturnIntByteArr:i];
memcpy(&i, fix, 4);
free(fix);
if (i == [_bufferData length]-4)
NSData *contentData = [_bufferData subdataWithRange:NSMakeRange(4, i)];
//完整接收了一条信息的处理
[self finishGetWholeData:contentData];
_bufferData = [NSMutableData data];
//需要拆包
else if (i & [_bufferData length]-4)
NSData *contentData = [_bufferData subdataWithRange:NSMakeRange(4, i)];
//这是完成了第一个包的数据的接收
[self finishGetWholeData:contentData];
NSData *buffer = [_bufferData subdataWithRange:NSMakeRange(i+4, _bufferData.length-i-4)];
_bufferData = [NSMutableData data];
[_bufferData appendData:buffer];
//继续进行判断处理
[self handleBufferData:nil];
大概就是酱紫.思路是这样,但是估摸着是会有一些问题的,以后使用中再慢慢完善吧~
&标签:&&&&&&&&&&&&&&&&&&&&&&&&原文:/forhonour/p/3916191.html
教程昨日排行
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!Pages: 1/2
主题 : 关于GCDAsyncSocket 接收数据 的问题
级别: 新手上路
UID: 507642
可可豆: 46 CB
威望: 35 点
在线时间: 200(时)
发自: Web Page
来源于&&分类
关于GCDAsyncSocket 接收数据 的问题&&&
大神们好刚开始接触TCP的数据传输 可以用GCDAsyncSocket 发送数据 但是接收数据只能接收一次(即didReadData 方法只调用一次)当网络调试软件发送第一次数据我是可以接收到的但是发送第二次以后 虽然xCode有提示有流量 产生 但是代理函数不调用 这是为什么呢?以下是我的代码- (void)viewDidLoad {&&&&[super viewDidLoad];&&&&// Do any additional setup after loading the view from its nib.&&&&&&&&self.navigationItem.title = @&发送&
请把代码粘贴在这里
;&&&&&&&&[self showNavItem];&&&&[self createClientTcpSocket];}- (void) showNavItem {&&&&UIBarButtonItem *sendMsg = [[UIBarButtonItem alloc] initWithTitle:@&发送消息& style:UIBarButtonItemStylePlain target:self action:@selector(sendMsg)];&&&&self.navigationItem.rightBarButtonItem = sendM}- (void) createClientTcpSocket {&&&&dispatch_queue_t dQueue = dispatch_queue_create(&client tdp socket&, NULL);&&&&// 1. 创建一个 udp socket用来和服务端进行通讯&&&&sendTcpSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dQueue socketQueue:nil];&&&&// 2. 连接服务器端. 只有连接成功后才能相互通讯 如果60s连接不上就出错&&&&NSString *host = SocketH&&&&uint16_t port = SocketP&&&&[sendTcpSocket connectToHost:host onPort:port withTimeout:60 error:nil];&&&&// 连接必须服务器在线}#pragma mark - 代理方法表示连接成功/失败 回调函数- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {&&&&NSLog(@&连接成功&);&&&&// 等待数据来啊&&&&[sock readDataWithTimeout:-1 tag:200];}// 如果对象关闭了 这里也会调用- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {&&&&NSLog(@&连接失败 %@&, err);&&&&// 断线重连&&&&NSString *host = SocketH&&&&uint16_t port = SocketP&&&&[sendTcpSocket connectToHost:host onPort:port withTimeout:60 error:nil];}#pragma mark - 消息发送成功 代理函数- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {&&&&[MBProgressHUD hideHUDForView:self.view animated:YES];&&&&NSLog(@&消息发送成功&);}- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {&&&&NSString *ip = [sock connectedHost];&&&&uint16_t port = [sock connectedPort];&&&&NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];&&&&NSLog(@&接收到服务器返回的数据 tcp [%@:%d] %@&, ip, port, s);}- (void) sendMsg {&&&&// 写这里代码&&&&NSString *s = @&hello from yang&;&&&&NSData *data = [s dataUsingEncoding:NSUTF8StringEncoding];&&&&// 开始发送&&&&[MBProgressHUD showHUDAddedTo:self.view animated:YES];&&&&// 发送消息 这里不需要知道对象的ip地址和端口&&&&[sendTcpSocket writeData:data withTimeout:60 tag:100];}- (void)dealloc {&&&&NSLog(@&dealloc&);&&&&// 关闭套接字&&&&[sendTcpSocket disconnect];&&&&sendTcpSocket =}- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {&&&&NSLog(@&Received bytes: %zd&,partialLength);}
描述:可以发送消息
图片:721F8136-C1EB-4646-80AC-32FA1C9560C5.png
描述:可以接受第一次消息
图片:9E67EA70-66D2-4194-AFF9-BC32D3F4A35C.png
描述:1.发送多条消息
图片:5FFD0BE1-D1B1-4252-B4BA-89FDC6AA9422.png
描述:2.能检测到流量
图片:E3E5AE8-BCEF-58C.png
描述:3.不调用代理方法
图片:9E67EA70-66D2-4194-AFF9-BC32D3F4A35C 2.png
级别: 新手上路
UID: 514164
可可豆: 29 CB
威望: 27 点
在线时间: 28(时)
发自: Web Page
因为你只在连接成功后设置了一次超时时间。每当你接收到数据之后,需要再次设置[sock readDataWithTimeout:-1 tag:200];把这句加到didReadData里面再试一下
级别: 新手上路
UID: 507642
可可豆: 46 CB
威望: 35 点
在线时间: 200(时)
发自: Web Page
回 1楼(萝莉即正义) 的帖子
问题解决啦 谢谢大神!!
级别: 新手上路
UID: 507642
可可豆: 46 CB
威望: 35 点
在线时间: 200(时)
发自: Web Page
回 1楼(萝莉即正义) 的帖子
额 如果可以的话我想问下 这个超时时间是用来干什么的呢? 设置了之后会有什么作用呢OvO
级别: 新手上路
UID: 514164
可可豆: 29 CB
威望: 27 点
在线时间: 28(时)
发自: Web Page
当过了超时时间服务器还未响应,说明网络拥堵或异常,你可以选择重新发送、提醒用户网络不稳定等操作。-1代表没有超时时间。超时后回回调方法。-(NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length你可以在这里进行重新发送或停止发送等操作。***********************************(新人理解,不对的地方还请更正)
级别: 新手上路
UID: 507642
可可豆: 46 CB
威望: 35 点
在线时间: 200(时)
发自: Web Page
回 4楼(萝莉即正义) 的帖子
猴 谢谢大神
级别: 圣骑士
UID: 565200
可可豆: 1824 CB
威望: 1486 点
在线时间: 687(时)
发自: Web Page
楼主&&我也遇到了这种情况 麻烦帮我看下 我发帖了
驾驭命运的舵是奋斗。不抱有一丝幻想,不放弃一点机会,不停止一日努力。
级别: 圣骑士
UID: 565200
可可豆: 1824 CB
威望: 1486 点
在线时间: 687(时)
发自: Web Page
楼主 为什么我是发送能接收 在发送就接收不到了发送数据为!!!!!!!!!& 03fce33 2e12e31 2e08 01 35 35 00 &与服务器连接成功!接收数据为!!!!!!!!(&&&&0,&&&&0,&&&&0,&&&&0,&&&&&0.000000&,&&&&&0.000000&)发送数据为!!!!!!!!!& 03fce33 2e12e31 2e08 01 35 35 00 &
驾驭命运的舵是奋斗。不抱有一丝幻想,不放弃一点机会,不停止一日努力。
级别: 圣骑士
UID: 565200
可可豆: 1824 CB
威望: 1486 点
在线时间: 687(时)
发自: Web Page
回 1楼(萝莉即正义) 的帖子
麻烦 问下 出现这种情况怎么办发送数据为!!!!!!!!!& 03fce33 2e12e31 2e08 01 35 35 00 &与服务器连接成功!接收数据为!!!!!!!!(&&&&0,&&&&0,&&&&0,&&&&0,&&&&&0.000000&,&&&&&0.000000&)发送数据为!!!!!!!!!& 03fce33 2e12e31 2e08 01 35 35 00 &
驾驭命运的舵是奋斗。不抱有一丝幻想,不放弃一点机会,不停止一日努力。
级别: 新手上路
可可豆: 3 CB
威望: 3 点
在线时间: 37(时)
发自: Web Page
回 1楼(萝莉即正义) 的帖子
谢谢,牛逼
Pages: 1/2
关注本帖(如果有新回复会站内信通知您)
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 关注CVP公众号
扫一扫 浏览移动版本帖子已过去太久远了,不再提供回复功能。iOS 中设备之间 socket 传文件应该怎么实现? - 知乎138被浏览21899分享邀请回答/2011/03/http-web-server-file-upload-on-iphone.html 251 条评论分享收藏感谢收起61 条评论分享收藏感谢收起查看更多回答}

我要回帖

更多关于 短数据包调度 时延 5g 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信