ios客户端socket通讯(二)

前言

写上一篇文章之前完全是想总结一下自己对socket通讯流程的总结,加深自己的印象,没有想到会有很多人关注这一块,再说自己是个socket的新手,写出来的文章没有多少人去看,所以上一篇文章写得不是很详细,但是发现还是有很多人关注,所以我就趁今天是个周末,花个2,3小时来总结一下本周socket通讯的进程,供想要了解的朋友参考。

正文

首先提一下网上CocoaAsyncSocket框架主要包括AsyncSocketGCDSocket,我使用的是后者,就是多线程Socket,主要区别就是前者基于NSRunLoop,后者是在多线程进行,据我项目目前的情况来看,GCDSocket内至少开辟了5个线程。
自己项目目前的进度是将socket单独封装成一个单独的类,也就是写成一个单例类,这样写的好处显而易见,这样我们建立通讯连接,数据请求就方便了很多,因为我们不可能去每一个需要数据的界面去创建socket进行连接,想办法把问题简单化使我们程序员必须做的重要一部分。想必网上关于socket的文章大多数都是大家你抄我我抄你而来,写一下socket创建,建立连接,实现代理方法,收发数据,没有更深一步的文章。其次大家有没有这样的一个疑惑,网上为什么没有开源的关于socket通讯的集成好的第三方框架供我使用呢?我直接收发数据就好了,还要那么麻烦建立连接,一堆问题去处理。像普通的网络数据请求,网上有封装好的AFNetworking,为什么socket没有!!!那我来告诉你基于socket的TCP的长连接往往数据传输协议是自定义的,所以这个不可能有现成的框架来用,必须根据自己的定义类型来收发数据,否则就无法解析。举个例子,我收数据需要这样的格式[^1^2],那当我收到数据data我必须得按这种格式校验,否则我就无法收到。上面首先将socket的逻辑说清楚,下面我们上代码,首先说明一点,我这个单例封装的我个人觉得比较完美,跟普通网络请求数据那种格式一某一样,最大的不同我是采用代理的方式回传数据,而不是block

#import "GCDAsyncSocket.h"

@protocol GPSSocketServeDelegate <NSObject>

/*** 连接服务器成功以后回调  */
- (void)connectSeverSucess:(NSString *)sucess;

/***  登录返回判断 */
- (void)ClickIsSucess:(BOOL)isSucess StrParam2:(NSString *)strParam2;

/***  返回请求数据 */
- (void)ClintReceCommData:(NSMutableArray *)data StrDataType:(NSString *)strDataType strParam2:(NSString *)strParam2;

@end


@class GPSSocketServeDelegate;
@interface GPSSocketServe : NSObject <GCDAsyncSocketDelegate>


@property (nonatomic,weak) id<GPSSocketServeDelegate>delegate;
@property (nonatomic,strong) GCDAsyncSocket *socket;

//在.h文件里面我给出了以下6个接口,建立连接,断开连接,其他的就是请求数据接口的封装

/***  获取本类对象 */

+ (GPSSocketServe *)sharedSocketServe;

/***  socket连接 */

- (void)startConnectSocket;


/***  断开socket开始连接 */

- (void)disConnectSocket;


/**
 *  登录接口
 *
 *  @param username 用户名
 *  @param password 用户密码
 */
- (void)userClick:(NSString *)username UserPassword:(NSString *)password;

/**
 *  用户登录调第一集部门表
 *
 *  @param p_strManagerCode 为用户的最高部门code
 *  @param p_strWGLoginName 用户名称
 */
- (void)requestManagerDep:(NSString *)p_strManagerCode P_strWGLoginName:(NSString *)p_strWGLoginName;

/**
 *  用户调第二级以及以后的部门表
 *
 *  @param p_strManagerCode    为当前级的部门code
 *  @param p_strCurrentDepName 为当前级的部门名称
 */
- (void)requestSencondManagerDep:(NSString *)p_strCurrentDepCode P_strCurrentDepName:(NSString *)p_strCurrentDepName;

/**
 *  调查询部门下的车辆列表
 *
 *  @param p_strManagerCode    为当前级的部门code
 *  @param p_strCurrentDepName 为当前级的部门名称
 */
- (void)requestCarsOfDep:(NSString *)p_strCurrentDepCode P_strCurrentDepName:(NSString *)p_strCurrentDepName;

GPSSocketServe.m文件,接口的实现
//创建单例对象,重写allocWithZone方法,保证这个对象在内存中只有一份
+ (GPSSocketServe *)sharedSocketServe{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        socketServe = [[self alloc] init];
    });

    return socketServe;
}

+(id)allocWithZone:(NSZone *)zone
{
    @synchronized(self)
    {
        if (socketServe == nil)
        {
            socketServe = [super allocWithZone:zone];
            return socketServe;
        }
    }
    return nil;
}
- (void)startConnectSocket
{
 //这个里面主要就是创建socket对象,建立连接,代码就不考了,可以参照上一篇


}

然后我说说我主要遇到的问题吧
1.原始的收到数据和我发送数据是在两个不同的方法里面,我们如何回传数据?
2.当我调用一级部门表的时候,发现收不到回传数据,然后一步一步的调,发现我发送的数据少5个字符长度,这个哪里出了问题?
关于第一个问题,其实我第一个感觉就是使用block,这样呢回传数据感觉很方便,例如当我发送登陆,就可以收到回调成功然后进行跳转,当时我已经成功实现了block回传数据,大概写一下实现的方法

//定义一个全局的block
//原因:发送请求和收到数据的不在一个方法里面
//定义一个block,申明一个属性,这个block带两个参数,一个是类型的字符串,另一个便是回传数据
typedef void(^requestDataBlock)(NSString *string,NSMutableArray *data);
@property (nonatomic,copy) requestDataBlock dataBlock;
//发送数据的同一接口
- (void)ClintSendCommData:(short)intDataType strDataType:(NSString *)strDataType stSetType:(NSString *)stSetType strSetSN:(NSString *)strSetSN strSetSN1:(NSString *)strSetSN1 strAlmComType:(NSString *)strAlmComType strHisType:(NSString *)strHisType strPosType:(NSString *)strPosType strFadeType:(NSString *)strFadeType strRecogType:(NSString *)strRecogType strRecogType1:(NSString *)strRecogType1 StrParam1:(NSString *)strParam1 StrParam2:(NSString *)strParam2 StrParam3:(NSString *)strParam3 StrParam4:(NSString *)strParam4 StrParam5:(NSString *)strParam5 StrParam6:(NSString *)strParam6 StrParam7:(NSString *)strParam7 StrParam8:(NSString *)strParam8

//在这个方法后面添加上block `success:(^requestDataBlock)(NSString *string,NSMutableArray *data)`
//在这个方法里面self.dataBlock = requestDataBlock;
//再接收数据的方法里面回调block
self.dataBlock(参数一,返回数据);

这样的话就实现了block回调数据,比较容易,前提是你对block足够的了解。
可是为什么我放弃了这个方法了,因为1.代码的冗余率太多,因为是多线程,当我更新UI我必须回到主线程,这个代码得多大一块;而且2.可扩展性不好,这个登录接口需要回传一个参数,调用需要回传多个参数,这样共用性不好,所以我就想到了代理,不同的接口我调用不同的代理方法,以后再有新的类型回传数据,我大不了再写一个回传接口而已。回调函数请看上面。

//这个就是后台提供给我的登录接口,这写也是用Java写的,不过我已经将他们改成oc的方法
ClintSendCommData(1105, "0002", "", "", "", "", "", "", "", "", "", p_strWGLoginName,p_strWGPassword, "", "", "", "", "", "");

大家一看这调用接口,需要传的参数就两个,所以你们想到了什么?反正我想到的是再封装一层

- (void)userClick:(NSString *)username UserPassword:(NSString *)password
{
    [self ClintSendCommData:1105 strDataType:@"0002" stSetType:@"" strSetSN:@"" strSetSN1:@"" strAlmComType:@"" strHisType:@"" strPosType:@"" strFadeType:@"" strRecogType:@"" strRecogType1:@"" StrParam1:username StrParam2:password StrParam3:@"" StrParam4:@"" StrParam5:@"" StrParam6:@"" StrParam7:@"" StrParam8:@""];
}

这样我就调用这个方法就OK,其他的调用数据的方法类似。

第二个问题出在什么地方呢?其实还是跟上一篇文章编码有关,后台服务器采用的是GB2312,我将它转换为UTF-8了,在发送数据的时候

//自定义发送数据接口,底层其实是调用发送数据的方法,writedata:,我只不过封装了一层
[self SendData:intDataType CharDatahead:(char *)[strData cStringUsingEncoding:enc] DataLen:intDataLen];

前面提到,我发送时候少了5个字符,这是跟我发送的里面包含了汉字,汉字的一般占用2个字符,而我们普通计算这个长度length当做一个字符来算,所以intDataLen计算是不对的,登录接口之所以对,那是因为没有汉字,我首先在计算长度的NSString的方法里面没有找到相应的方法,不知道有没有朋友找到,有找到的可以留言给我,非常感谢!那我说说我在网上找到的计算包含汉字的方法(其实这个方法是经过我改造过的方法)

/**
 *  计算包含中文的字符的字符串长度
 */
-(int)lengthOfStringContainChinese:(NSString*)c{
    
    int strlength = 0;
    char* p = (char*)[c cStringUsingEncoding:NSUnicodeStringEncoding];
    
    for (int i=0 ; i<[c lengthOfBytesUsingEncoding:NSUnicodeStringEncoding] ;i++) {
        if (*p) {
            p++;
            strlength++;
        }
        else {
            p++;
        }
    }
    return strlength;
}

这样计算就正确了。
以上是我在解决的主要问题,其实我在真机调试的时候,发现了一个比较严重的问题,在网络请求的时候,网络不好,会出现严重的内存暴增,程序就会闪退,不过这个问题我已经解决掉了,通过的是调试工具,这个下一期我会教大家调试的方法,首先科普一下,手机内存一般达到30M的话就会自动闪退,有遇到这个问题的朋友可以仔细研究研究。

简易的程序运行
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它...
    Ethan_Struggle阅读 2,197评论 2 12
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,107评论 29 470
  • iOS网络架构讨论梳理整理中。。。 其实如果没有APIManager这一层是没法使用delegate的,毕竟多个单...
    yhtang阅读 5,144评论 1 23
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,137评论 11 349
  • 春天来了,一对燕子夫妇从南方飞回来,在豪豪家屋檐下筑巢,当天就下了五个蛋,燕妈妈每天窝在巢里孵小燕子呢。 豪豪早就...
    亦诺1阅读 179评论 2 11