ios客戶端socket通訊(二)

前言

寫(xiě)上一篇文章之前完全是想總結(jié)一下自己對(duì)socket通訊流程的總結(jié)班巩,加深自己的印象,沒(méi)有想到會(huì)有很多人關(guān)注這一塊,再說(shuō)自己是個(gè)socket的新手,寫(xiě)出來(lái)的文章沒(méi)有多少人去看鹰椒,所以上一篇文章寫(xiě)得不是很詳細(xì),但是發(fā)現(xiàn)還是有很多人關(guān)注券坞,所以我就趁今天是個(gè)周末,花個(gè)2,3小時(shí)來(lái)總結(jié)一下本周socket通訊的進(jìn)程,供想要了解的朋友參考寺渗。

正文

首先提一下網(wǎng)上CocoaAsyncSocket框架主要包括AsyncSocketGCDSocket,我使用的是后者兰迫,就是多線程Socket信殊,主要區(qū)別就是前者基于NSRunLoop,后者是在多線程進(jìn)行逮矛,據(jù)我項(xiàng)目目前的情況來(lái)看鸡号,GCDSocket內(nèi)至少開(kāi)辟了5個(gè)線程转砖。
自己項(xiàng)目目前的進(jìn)度是將socket單獨(dú)封裝成一個(gè)單獨(dú)的類须鼎,也就是寫(xiě)成一個(gè)單例類鲸伴,這樣寫(xiě)的好處顯而易見(jiàn),這樣我們建立通訊連接晋控,數(shù)據(jù)請(qǐng)求就方便了很多汞窗,因?yàn)槲覀儾豢赡苋ッ恳粋€(gè)需要數(shù)據(jù)的界面去創(chuàng)建socket進(jìn)行連接,想辦法把問(wèn)題簡(jiǎn)單化使我們程序員必須做的重要一部分赡译。想必網(wǎng)上關(guān)于socket的文章大多數(shù)都是大家你抄我我抄你而來(lái)仲吏,寫(xiě)一下socket創(chuàng)建,建立連接蝌焚,實(shí)現(xiàn)代理方法裹唆,收發(fā)數(shù)據(jù),沒(méi)有更深一步的文章只洒。其次大家有沒(méi)有這樣的一個(gè)疑惑许帐,網(wǎng)上為什么沒(méi)有開(kāi)源的關(guān)于socket通訊的集成好的第三方框架供我使用呢?我直接收發(fā)數(shù)據(jù)就好了毕谴,還要那么麻煩建立連接成畦,一堆問(wèn)題去處理。像普通的網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求涝开,網(wǎng)上有封裝好的AFNetworking循帐,為什么socket沒(méi)有!Rㄎ洹拄养!那我來(lái)告訴你基于socket的TCP的長(zhǎng)連接往往數(shù)據(jù)傳輸協(xié)議是自定義的,所以這個(gè)不可能有現(xiàn)成的框架來(lái)用银舱,必須根據(jù)自己的定義類型來(lái)收發(fā)數(shù)據(jù)衷旅,否則就無(wú)法解析。舉個(gè)例子纵朋,我收數(shù)據(jù)需要這樣的格式[^1^2],那當(dāng)我收到數(shù)據(jù)data我必須得按這種格式校驗(yàn)柿顶,否則我就無(wú)法收到。上面首先將socket的邏輯說(shuō)清楚操软,下面我們上代碼嘁锯,首先說(shuō)明一點(diǎn),我這個(gè)單例封裝的我個(gè)人覺(jué)得比較完美聂薪,跟普通網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)那種格式一某一樣家乘,最大的不同我是采用代理的方式回傳數(shù)據(jù),而不是block藏澳。

#import "GCDAsyncSocket.h"

@protocol GPSSocketServeDelegate <NSObject>

/*** 連接服務(wù)器成功以后回調(diào)  */
- (void)connectSeverSucess:(NSString *)sucess;

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

/***  返回請(qǐng)求數(shù)據(jù) */
- (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個(gè)接口仁锯,建立連接,斷開(kāi)連接翔悠,其他的就是請(qǐng)求數(shù)據(jù)接口的封裝

/***  獲取本類對(duì)象 */

+ (GPSSocketServe *)sharedSocketServe;

/***  socket連接 */

- (void)startConnectSocket;


/***  斷開(kāi)socket開(kāi)始連接 */

- (void)disConnectSocket;


/**
 *  登錄接口
 *
 *  @param username 用戶名
 *  @param password 用戶密碼
 */
- (void)userClick:(NSString *)username UserPassword:(NSString *)password;

/**
 *  用戶登錄調(diào)第一集部門(mén)表
 *
 *  @param p_strManagerCode 為用戶的最高部門(mén)code
 *  @param p_strWGLoginName 用戶名稱
 */
- (void)requestManagerDep:(NSString *)p_strManagerCode P_strWGLoginName:(NSString *)p_strWGLoginName;

/**
 *  用戶調(diào)第二級(jí)以及以后的部門(mén)表
 *
 *  @param p_strManagerCode    為當(dāng)前級(jí)的部門(mén)code
 *  @param p_strCurrentDepName 為當(dāng)前級(jí)的部門(mén)名稱
 */
- (void)requestSencondManagerDep:(NSString *)p_strCurrentDepCode P_strCurrentDepName:(NSString *)p_strCurrentDepName;

/**
 *  調(diào)查詢部門(mén)下的車輛列表
 *
 *  @param p_strManagerCode    為當(dāng)前級(jí)的部門(mén)code
 *  @param p_strCurrentDepName 為當(dāng)前級(jí)的部門(mén)名稱
 */
- (void)requestCarsOfDep:(NSString *)p_strCurrentDepCode P_strCurrentDepName:(NSString *)p_strCurrentDepName;

GPSSocketServe.m文件业崖,接口的實(shí)現(xiàn)
//創(chuàng)建單例對(duì)象野芒,重寫(xiě)allocWithZone方法,保證這個(gè)對(duì)象在內(nèi)存中只有一份
+ (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
{
 //這個(gè)里面主要就是創(chuàng)建socket對(duì)象双炕,建立連接狞悲,代碼就不考了,可以參照上一篇


}

然后我說(shuō)說(shuō)我主要遇到的問(wèn)題吧
1.原始的收到數(shù)據(jù)和我發(fā)送數(shù)據(jù)是在兩個(gè)不同的方法里面妇斤,我們?nèi)绾位貍鲾?shù)據(jù)摇锋?
2.當(dāng)我調(diào)用一級(jí)部門(mén)表的時(shí)候,發(fā)現(xiàn)收不到回傳數(shù)據(jù)站超,然后一步一步的調(diào)荸恕,發(fā)現(xiàn)我發(fā)送的數(shù)據(jù)少5個(gè)字符長(zhǎng)度,這個(gè)哪里出了問(wèn)題死相?
關(guān)于第一個(gè)問(wèn)題戚炫,其實(shí)我第一個(gè)感覺(jué)就是使用block,這樣呢回傳數(shù)據(jù)感覺(jué)很方便媳纬,例如當(dāng)我發(fā)送登陸双肤,就可以收到回調(diào)成功然后進(jìn)行跳轉(zhuǎn),當(dāng)時(shí)我已經(jīng)成功實(shí)現(xiàn)了block回傳數(shù)據(jù)钮惠,大概寫(xiě)一下實(shí)現(xiàn)的方法

//定義一個(gè)全局的block
//原因:發(fā)送請(qǐng)求和收到數(shù)據(jù)的不在一個(gè)方法里面
//定義一個(gè)block茅糜,申明一個(gè)屬性,這個(gè)block帶兩個(gè)參數(shù)素挽,一個(gè)是類型的字符串蔑赘,另一個(gè)便是回傳數(shù)據(jù)
typedef void(^requestDataBlock)(NSString *string,NSMutableArray *data);
@property (nonatomic,copy) requestDataBlock dataBlock;
//發(fā)送數(shù)據(jù)的同一接口
- (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

//在這個(gè)方法后面添加上block `success:(^requestDataBlock)(NSString *string,NSMutableArray *data)`
//在這個(gè)方法里面self.dataBlock = requestDataBlock;
//再接收數(shù)據(jù)的方法里面回調(diào)block
self.dataBlock(參數(shù)一,返回?cái)?shù)據(jù));

這樣的話就實(shí)現(xiàn)了block回調(diào)數(shù)據(jù)预明,比較容易缩赛,前提是你對(duì)block足夠的了解。
可是為什么我放棄了這個(gè)方法了撰糠,因?yàn)?.代碼的冗余率太多酥馍,因?yàn)槭嵌嗑€程,當(dāng)我更新UI我必須回到主線程阅酪,這個(gè)代碼得多大一塊旨袒;而且2.可擴(kuò)展性不好,這個(gè)登錄接口需要回傳一個(gè)參數(shù)术辐,調(diào)用需要回傳多個(gè)參數(shù)砚尽,這樣共用性不好,所以我就想到了代理辉词,不同的接口我調(diào)用不同的代理方法必孤,以后再有新的類型回傳數(shù)據(jù),我大不了再寫(xiě)一個(gè)回傳接口而已瑞躺》筇拢回調(diào)函數(shù)請(qǐng)看上面兴想。

//這個(gè)就是后臺(tái)提供給我的登錄接口,這寫(xiě)也是用Java寫(xiě)的购啄,不過(guò)我已經(jīng)將他們改成oc的方法
ClintSendCommData(1105, "0002", "", "", "", "", "", "", "", "", "", p_strWGLoginName,p_strWGPassword, "", "", "", "", "", "");

大家一看這調(diào)用接口襟企,需要傳的參數(shù)就兩個(gè)嘱么,所以你們想到了什么狮含?反正我想到的是再封裝一層

- (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:@""];
}

這樣我就調(diào)用這個(gè)方法就OK,其他的調(diào)用數(shù)據(jù)的方法類似曼振。

第二個(gè)問(wèn)題出在什么地方呢几迄?其實(shí)還是跟上一篇文章編碼有關(guān),后臺(tái)服務(wù)器采用的是GB2312冰评,我將它轉(zhuǎn)換為UTF-8了映胁,在發(fā)送數(shù)據(jù)的時(shí)候

//自定義發(fā)送數(shù)據(jù)接口,底層其實(shí)是調(diào)用發(fā)送數(shù)據(jù)的方法甲雅,writedata:解孙,我只不過(guò)封裝了一層
[self SendData:intDataType CharDatahead:(char *)[strData cStringUsingEncoding:enc] DataLen:intDataLen];

前面提到,我發(fā)送時(shí)候少了5個(gè)字符抛人,這是跟我發(fā)送的里面包含了漢字弛姜,漢字的一般占用2個(gè)字符,而我們普通計(jì)算這個(gè)長(zhǎng)度length當(dāng)做一個(gè)字符來(lái)算妖枚,所以intDataLen計(jì)算是不對(duì)的廷臼,登錄接口之所以對(duì),那是因?yàn)闆](méi)有漢字绝页,我首先在計(jì)算長(zhǎng)度的NSString的方法里面沒(méi)有找到相應(yīng)的方法荠商,不知道有沒(méi)有朋友找到,有找到的可以留言給我续誉,非常感謝莱没!那我說(shuō)說(shuō)我在網(wǎng)上找到的計(jì)算包含漢字的方法(其實(shí)這個(gè)方法是經(jīng)過(guò)我改造過(guò)的方法)

/**
 *  計(jì)算包含中文的字符的字符串長(zhǎng)度
 */
-(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;
}

這樣計(jì)算就正確了。
以上是我在解決的主要問(wèn)題酷鸦,其實(shí)我在真機(jī)調(diào)試的時(shí)候郊愧,發(fā)現(xiàn)了一個(gè)比較嚴(yán)重的問(wèn)題,在網(wǎng)絡(luò)請(qǐng)求的時(shí)候井佑,網(wǎng)絡(luò)不好属铁,會(huì)出現(xiàn)嚴(yán)重的內(nèi)存暴增,程序就會(huì)閃退躬翁,不過(guò)這個(gè)問(wèn)題我已經(jīng)解決掉了焦蘑,通過(guò)的是調(diào)試工具,這個(gè)下一期我會(huì)教大家調(diào)試的方法盒发,首先科普一下例嘱,手機(jī)內(nèi)存一般達(dá)到30M的話就會(huì)自動(dòng)閃退狡逢,有遇到這個(gè)問(wèn)題的朋友可以仔細(xì)研究研究。

簡(jiǎn)易的程序運(yùn)行
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拼卵,一起剝皮案震驚了整個(gè)濱河市奢浑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腋腮,老刑警劉巖雀彼,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異即寡,居然都是意外死亡徊哑,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)聪富,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)莺丑,“玉大人,你說(shuō)我怎么就攤上這事墩蔓∩颐В” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵奸披,是天一觀的道長(zhǎng)昏名。 經(jīng)常有香客問(wèn)我,道長(zhǎng)源内,這世上最難降的妖魔是什么葡粒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮膜钓,結(jié)果婚禮上嗽交,老公的妹妹穿的比我還像新娘。我一直安慰自己颂斜,他們只是感情好夫壁,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著沃疮,像睡著了一般盒让。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上司蔬,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天邑茄,我揣著相機(jī)與錄音,去河邊找鬼俊啼。 笑死肺缕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播同木,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浮梢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了彤路?” 一聲冷哼從身側(cè)響起秕硝,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洲尊,沒(méi)想到半個(gè)月后远豺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颊郎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年憋飞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了霎苗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姆吭。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖唁盏,靈堂內(nèi)的尸體忽然破棺而出内狸,到底是詐尸還是另有隱情,我是刑警寧澤厘擂,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布昆淡,位于F島的核電站,受9級(jí)特大地震影響刽严,放射性物質(zhì)發(fā)生泄漏昂灵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一舞萄、第九天 我趴在偏房一處隱蔽的房頂上張望眨补。 院中可真熱鬧,春花似錦倒脓、人聲如沸撑螺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)甘晤。三九已至,卻和暖如春饲做,著一層夾襖步出監(jiān)牢的瞬間线婚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工盆均, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留塞弊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像居砖,于是被迫代替她去往敵國(guó)和親虹脯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • iPhone的標(biāo)準(zhǔn)推薦是CFNetwork 庫(kù)編程奏候,其封裝好的開(kāi)源庫(kù)是 cocoa AsyncSocket庫(kù)循集,用它...
    Ethan_Struggle閱讀 2,227評(píng)論 2 12
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,131評(píng)論 30 470
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中。蔗草。咒彤。 其實(shí)如果沒(méi)有APIManager這一層是沒(méi)法使用delegate的,畢竟多個(gè)單...
    yhtang閱讀 5,172評(píng)論 1 23
  • 從三月份找實(shí)習(xí)到現(xiàn)在咒精,面了一些公司镶柱,掛了不少,但最終還是拿到小米模叙、百度歇拆、阿里、京東范咨、新浪故觅、CVTE、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,211評(píng)論 11 349
  • 春天來(lái)了渠啊,一對(duì)燕子夫婦從南方飛回來(lái)输吏,在豪豪家屋檐下筑巢,當(dāng)天就下了五個(gè)蛋替蛉,燕媽媽每天窩在巢里孵小燕子呢贯溅。 豪豪早就...
    亦諾1閱讀 186評(píng)論 2 11