iOS使用GCDAsyncSocket實(shí)現(xiàn)消息推送

最近公司項(xiàng)目需要用到推送,但是公司的開發(fā)者賬號(hào)沒有申請(qǐng)好,無法使用遠(yuǎn)程推送失都,加上后臺(tái)大大說用第三方推送不方便調(diào)試,于是一起商定使用socket實(shí)現(xiàn)消息推送幸冻。

實(shí)現(xiàn)原理

利用socket與遠(yuǎn)程服務(wù)器建立長連接進(jìn)行消息通訊嗅剖,服務(wù)端通過檢測(cè)與客戶端的連接狀態(tài)進(jìn)行消息推送,客戶端收到數(shù)據(jù)后給服務(wù)器發(fā)送應(yīng)答消息讓服務(wù)器知道消息的投遞情況嘁扼。優(yōu)點(diǎn):調(diào)試方便,使用靈活黔攒。缺點(diǎn):無法實(shí)現(xiàn)App后臺(tái)接收消息趁啸。

主要實(shí)現(xiàn)代碼如下

  • 創(chuàng)建socket
// 屬性定義
// 超時(shí)等待時(shí)長
static NSUInteger timeout = 45;
// socket
@property(nonatomic,strong)GCDAsyncSocket *socket;
// 定時(shí)器
@property(nonatomic,strong)NSTimer *timer;
// 時(shí)間計(jì)數(shù)
@property(nonatomic,assign)NSUInteger count;
// 連接狀態(tài)標(biāo)識(shí)
@property(nonatomic,assign)BOOL isConnect;
// 登錄狀態(tài)標(biāo)識(shí)
@property(nonatomic,assign)BOOL isLogin;
// 重連計(jì)數(shù)
@property(nonatomic,assign)NSUInteger reconnectCount;

// 懶加載方法
- (GCDAsyncSocket *)socket {
    if (_socket == nil) {
        _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    return _socket;
}
- (NSTimer *)timer {
    if (_timer == nil) {
        _timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
        [_timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:0]];
        [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
    }
    return _timer;
}
  • 建立連接
- (void)startConnectWithURLStr:(NSString *)urlStr {
    // 開啟定時(shí)器
    self.timer.fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
    // 處理URL字符串
    NSRange range = [urlStr rangeOfString:@":"];
    NSString *host = [urlStr substringToIndex:range.location];
    NSString *port = [urlStr substringFromIndex:range.location+range.length];
    // 連接(如果已經(jīng)連接則調(diào)用登錄方法)
    if (self.socket.isConnected == NO) {
        [self.socket connectToHost:host onPort:port.integerValue error:nil];
        [self timer];
        NSLog(@"開始連接主機(jī):%@ 端口號(hào):%@",host,port);
    }
    else {
        [self startLogin];
    }
}
  • 向服務(wù)器發(fā)起登錄請(qǐng)求
// 登錄方法
- (void)startLogin {
    NSLog(@"開始登錄强缘。。不傅。");
    // 獲取登錄報(bào)文數(shù)據(jù)
    NSData *data = [self getLoginData];
    
    // 發(fā)送數(shù)據(jù)
    NSLog(@"發(fā)送登錄數(shù)據(jù):%@",data);
    [self.socket writeData:data withTimeout:timeout tag:0];
    // 啟動(dòng)socket讀數(shù)據(jù)等待(必須調(diào)用此方法才能收到服務(wù)器傳輸?shù)臄?shù)據(jù))
    [self.socket readDataWithTimeout:timeout tag:0];
    // 重置定時(shí)器計(jì)數(shù)
    _count = 0;
}
  • 登錄成功定時(shí)發(fā)送心跳包
// 定時(shí)器回調(diào)方法
- (void)timerAction {
// 計(jì)時(shí)遞增
    _count += 1;
    if (_isConnect) {       //連接成功
        if (_isLogin) {     //登錄成功
            if (_count >= 40) {  //每40秒進(jìn)行一次操作
                // 發(fā)送心跳包
                [self sendHeartBeatData];
                _count = 0;
            }
        }
        else {              //登錄失敗
            if (_count > timeout) {
                // 重登錄
                [self startLogin];
                NSLog(@"socket重新登錄!");
                _count = 0;
            }
        }
    }
    else {                  //連接失敗
        if (_count >= timeout) {
            // 重連
            [self startConnect];
            _reconnectCount+=1;
            NSLog(@"socket重新連接!--%zd次-",_reconnectCount);
            _count = 0;
        }
    }
}
  • 代理方法(GCDAsyncSocketDelegate)
// 即將連接到主機(jī)
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    NSLog(@"--socket--連接成功");
    // 重置重連接計(jì)數(shù)
    _reconnectCount = 0;
    // 置位連接狀態(tài)標(biāo)識(shí)
    _isConnect = YES;
    // 重設(shè)置定時(shí)計(jì)數(shù)
    _count = 0;
    // 啟動(dòng)登錄
    [self startLogin];
}
// socket連接斷開
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    if (err.code == 4) {
        // 讀取超時(shí)
        NSLog(@"獲取socket服務(wù)器回應(yīng)超時(shí)");
        // 手動(dòng)斷開并重連
        [self stopConnect];
        [self startConnect];
        return;
    }
    else if (err.code == 60) {
        NSLog(@"socket連接超時(shí)");
        // 手動(dòng)斷開并重連
        [self stopConnect];
        [self startConnect];
    }
    else {
        NSLog(@"--socket--連接失敗--err:%@",err);
        if (err != nil) {
        // 重置標(biāo)識(shí)位,定時(shí)重連
            _isConnect = NO;
            _isLogin = NO;
        }
    }
}
// 讀取到服務(wù)端發(fā)送的數(shù)據(jù)
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    
    NSLog(@"--socket--Read:%@",data);
    // 調(diào)用數(shù)據(jù)解析方法解析數(shù)據(jù)
    [self syntacticReadData:data];
    // 進(jìn)行下一次數(shù)據(jù)讀取
    [self.socket readDataWithTimeout:timeout tag:0];
}

  • 手動(dòng)斷開連接
// 手動(dòng)斷開連接方法
- (void)stopConnect {
    // 停止定時(shí)器
    self.timer.fireDate = [NSDate distantFuture];
    // 釋放socket連接
    [self.socket disconnect];
    // 設(shè)置檢查標(biāo)識(shí)
    _isConnect = NO;
    _isLogin = NO;
    // 重設(shè)重連計(jì)數(shù)
    _reconnectCount = 0;
    _count = 0;
    NSLog(@"斷開socket連接");
}

個(gè)人總結(jié)
第一次使用GCDAsyncSocket進(jìn)行開發(fā),剛開始以為創(chuàng)建socket之后設(shè)置好代理就可以從代理方法中讀取到服務(wù)器的回應(yīng)數(shù)據(jù)屋讶,可是一直都是可以發(fā)送數(shù)據(jù)給服務(wù)器而沒有收到服務(wù)器給的回應(yīng)數(shù)據(jù)(讀取數(shù)據(jù)的哪個(gè)代理方法根本就不走)怀酷,于是經(jīng)過一番百度查找才知道原來GCDAsyncSocket是需要手動(dòng)調(diào)用讀數(shù)據(jù)的方法并設(shè)定超時(shí)等待才能讀取到數(shù)據(jù)的,個(gè)人建議在發(fā)送數(shù)據(jù)的時(shí)候就調(diào)用一次讀數(shù)據(jù)的方法并設(shè)定好合適的超時(shí)等待時(shí)間崖疤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秘车,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劫哼,更是在濱河造成了極大的恐慌叮趴,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件权烧,死亡現(xiàn)場(chǎng)離奇詭異眯亦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)般码,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門妻率,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人板祝,你說我怎么就攤上這事宫静。” “怎么了扔字?”我有些...
    開封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵囊嘉,是天一觀的道長。 經(jīng)常有香客問我革为,道長扭粱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任震檩,我火速辦了婚禮琢蛤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抛虏。我一直安慰自己博其,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開白布迂猴。 她就那樣靜靜地躺著慕淡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沸毁。 梳的紋絲不亂的頭發(fā)上峰髓,一...
    開封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天傻寂,我揣著相機(jī)與錄音,去河邊找鬼携兵。 笑死疾掰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的徐紧。 我是一名探鬼主播静檬,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼并级!你這毒婦竟也來了拂檩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤死遭,失蹤者是張志新(化名)和其女友劉穎广恢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呀潭,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钉迷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钠署。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糠聪。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谐鼎,靈堂內(nèi)的尸體忽然破棺而出舰蟆,到底是詐尸還是另有隱情,我是刑警寧澤狸棍,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布身害,位于F島的核電站,受9級(jí)特大地震影響草戈,放射性物質(zhì)發(fā)生泄漏塌鸯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一唐片、第九天 我趴在偏房一處隱蔽的房頂上張望丙猬。 院中可真熱鬧,春花似錦费韭、人聲如沸茧球。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抢埋。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揪垄,已是汗流浹背鲤屡。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留福侈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓卢未,卻偏偏與公主長得像肪凛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辽社,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理伟墙,服務(wù)發(fā)現(xiàn),斷路器滴铅,智...
    卡卡羅2017閱讀 134,714評(píng)論 18 139
  • 多線程戳葵、特別是NSOperation 和 GCD 的內(nèi)部原理。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景汉匙。SDWebImage的原...
    LZM輪回閱讀 2,009評(píng)論 0 12
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 11,009評(píng)論 6 13
  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20170615/19529.html 參考:h...
    F麥子閱讀 4,012評(píng)論 3 2
  • 第一部分拱烁、概念的理解1、什么是Socket噩翠?Socket又稱之為“套接字”戏自,是系統(tǒng)提供的用于網(wǎng)絡(luò)通信的方法。它的實(shí)...
    Hevin_Chen閱讀 2,459評(píng)論 0 5