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

说来惭愧,搞了两年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上貌似没找到.只好手动.那首先要跟服务器有个协议,说明一下以什么作为一条信息的节点.比如我们,每条信息的头四个字节是用来保存这条信息的应有长度的.接到信息首先要读取长度,然后再跟收到的数据包长度对比.如果收到的长度刚刚好,说明这是一条完整的信息,直接封起来就行.如果收到的长度比预计长度短,说明信息被拆包发送,那就要继续跟下一个包进行拼装,再检验长度.如果收到的长度比预计的长,说明发生了粘包,那就要根据预计长度对数据包的数据进行拆分,对拆出的两部分数据继续进行处理.

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

 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     

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

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

时间: 2024-10-10 09:54:07

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

阅读《大型网站技术架构》前两章心得体会及总结

最近阅读了<大型网站技术架构>这一本书,对于这一行业刚入门的菜鸟来说,虽然只读了前两章,却让我感受颇深,同时也学习和见识到了很多之前不了解.不明白的东西. 通过阅读前两章,我才真正的初步明白了一个刚刚成型的小型网站是如何一步一步的成长为一个大型网站.从网站的最开始的基础架构,到一步步实现网站的性能提升,到如何处理网站的高并发数据,到使用反响代理和CDN加速网站响应,让我一步一步的真正的认识到了架构的重要性,也让我这个菜鸟学习到了很多之前不懂的知识. 第一章主要讲授了大型网站架构演化的发展历程,

php如何获取到前两个页面的url

自己在学习过程中也遇到了类似的问题: 比如,后台是想做成这样子的: 但是实际则是这样的: 解决方法: 通过表单隐藏控件 <input type="hidden" name="prevurl" value="<?php echo $_SERVER['HTTP_REFERER']?>"> 这样$_SERVER['HTTP_REFERER']的值就暂时存到了$_POST[prevurl]里. 暂时没想到更好的方法. php如何获

BestCoder Round #4 前两题 hdu 4931 4932

第一题太水了.. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int a[6]; 7 int main(){ 8 int cas; 9 scanf( "%d", &cas ); 10 while( cas-- ){ 11 for( int i = 0; i <

前两天有人问怎么取得一个目录下的文件,下面就是例子

<%@ Language=VBScript %> <% '================================================================ '函数名称:FileList '函数功能:列出目录下所有文件 '主要参数说明: '1--FolderUrl 虚拟路径 不可为空 '2----FileExName 文件扩展名 '函数返回值:收文记录 '====================================================

百度网盘,前几天刚从百度云改名过来,百度云这个名字给之前的百度开放云(同步盘用户比较小众)good

作者:黑郁金香链接:http://www.zhihu.com/question/51803053/answer/127562835来源:知乎著作权归作者所有,转载请联系作者获得授权. 在8月网盘大面积关闭的时候我回答过类似的问题目前(2016 年 8 月),市面上哪个云同步盘最好用? - 知乎用户的回答现在还能用的免费大容量网盘:百度网盘(刚从百度云改名过来).微云.天翼云.115等先放观点:对非主营业务的大容量免费网盘我都不看好.理由: 同步盘用户比较小众,并且从几个还存活的网盘关闭同步功能来

WORD中如何让前两页不显示页码

WORD中如何让前两页不显示页码   上稿人:ojn 点击率: 15191   我们有时在用word编辑文档时,会遇上第一.二页无需显示页码,第三页才是正文的第一页时,该如何正确插入页码呢? 以word 2010为例,方法如下: 假如第1-2页无页码,第3页开始插入页码,起始页为1. 1.将光标定位在第2页末尾处,点击“页面布局——(页面设置)分隔符——(分节符)下一页” 2.双击第3页的页脚处,进入页眉和页脚的编辑状态,点击工具栏中的“链接到前一条页眉”按钮,使其使其退出高亮状态. 3.点击“

混血妆容教程 妆前两步排水肿不脱妆

混血妆容教程 妆前两步排水肿不脱 http://baozoumanhua.com/users/13998545/forum_articleshttp://baozoumanhua.com/users/13998544/forum_articleshttp://baozoumanhua.com/users/13998551/forum_articleshttp://baozoumanhua.com/users/13998554/forum_articleshttp://baozoumanhua.c

央行房贷新政带火北京学区房:相比前两月涨10%

央行房贷新政带火北京学区房:相比前两月涨10% 行业动态经济参考报[微博]2014-10-24 01:26 我要分享 3 央行发布<关于进一步做好住房金融服务工作的通知>(下称房贷新政)半个多月,多个权威机构数据显示,改善型市场明显回暖.其中,学区房因为突出的资源优势,领“涨”市场.虽然有利好政策“助威”,但房企依然表现冷静,多数采取平价走量的策略,业内人士分析认为,这为诸多改善型置业群体打开了购房窗口. 为市场打了一剂“强心针” 房贷新政出台以来,记者走访领秀·翡翠山(楼盘资料).中冶德贤公

前两篇转载别人的精彩文章,自己也总结一下python split的用法吧!

前言:前两篇转载别人的精彩文章,自己也总结一下吧! 最近又开始用起py,是为什么呢? 自己要做一个文本相似度匹配程序,大致思路就是两个文档,一个是试题,一个是材料,我将试题按每题分割出来,再将每题的内容与材料中进行文本相似度匹配. 所以先首先要做的是将试题把每道题作为一个字符串切割开来,存放到字典中. 程序入下: # -*- coding:utf-8 -*- import re #正则模块 f = open('test.txt','r') s = f.read() s1 = s.split('工