WebScoket建立即时通讯聊天室--SocketRocket的使用

前言

在新公司入职的两个月时间里学习到了不少新的知识。其中聊天室就是近期在研究公司代码时学习碰到的一个技术点。其实在上一家公司也接触过做即时通讯的需求,但之前由于工期比较紧所以就选择了用环信(一个比较主流的第三方即时通讯sdk)来实现。但其中实现的原理没有深究,学到的东西并不多。因此借着这个机会拜读一下同事的代码,写下这篇学习笔记补充一下即时通讯这一块漏掉的知识。

实现方式

iOS 不用第三方sdk实现即时通讯的主流方法主要有4种:1、基于Scoket原生:代表框架 CocoaAsyncSocket。2、基于WebScoket:代表框架 SocketRocket。3、基于MQTT:代表框架 MQTTKit。4、基于XMPP:代表框架 XMPPFramework。这四种方式都各有利弊。我们公司选择的实现方式是基于WebSocket实现的,因此我先从这个方式入手,其他3种方式待以后探究。

什么是WebSocket?

我们在客户端开发的过程中,相信我们遇到最多的网络协议是HTTP协议。WebSocket 和HTTP 一样是网络协议的一种。那么我们已经有强大的HTTP协议了为什么还需要另外一种网络协议呢?那是因为HTTP协议有一个很大的弊端--通讯只能有客户端发起。客户端发起的request 和服务器下发的respond 是一一对应的。在HTTP协议下如果客户端有连续的状态变化,客户端想要获取就比较麻烦。我们只能依靠轮询机制(每隔一段时间向服务器请求一次,了解服务器最新的数据)来获取。但是轮询不但耗费性能,而且也并非真正意义上的实现即时性。这就导致HTTP 协议并不适合用于即时通讯。而WebSocket就是解决这一问题而发明的。WebSocket借用了HTTP的协议来完成一次握手,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据了。

如何在iOS项目中使用WebSocket

在上面介绍即时通讯的实现方式时提到,WebSocket的代表框架是SocketRocket。团队的项目也是用SocketRocket来实现聊天室功能的。因此我也来顺带了解一下SocketRocket这个框架。SocketRocket是Facebook开源的一个用于 iOS, macOS and tvOS客户端的websocket框架。SocketRocket是对WebSocket的封装。

1、集成

集成SocketRocket方法非常简单,用cocoapods 在podfile中加入 pod 'SocketRocket',执行pod install指令就可以完成集成。

2、实现聊天室功能需要做哪些事情?

那我们在一次建立一个即时聊天的过程中,我们需要做哪些事情呢?①、首先我们需要建立连接 ②、遵守并指定代理 ③、打开连接加载请求 ④、关闭连接 ⑤、发送消息 ⑥、通过代理方法来获取接收到的消息

-(void)SRWebSocketOpen{

            //如果是同一个url return

    if (self.socket) {

                return;

        }

    self.socket = [[SRWebSocket alloc] initWithURLRequest:                   [NSURLRequest requestWithURL:[NSURL URLWithString:@"ws:xxxxxxxxxxx"]]];//这里填写你服务器的地址

    self.socket.delegate = self;  //SRWebSocketDelegate 协议

            [self.socket open];    //开始连接

}

①、建立连接 ②、遵守并指定代理 ③、打开连接加载请求

在SRWebSocketOpen方法里,我们先创建一个SRWebSocket对象,并设置了SocketRocket的回调代理。在完成以上两个操作后,调用[_socket Open];开始建立连接。



-(void)SRWebSocketClose{

        if (self.socket){

                [self.socket close];

                self.socket = nil;

                //断开连接时销毁心跳

                [self destoryHeartBeat];

        }

}

④、关闭连接:

在SRWebSocketClose方法里,通过调用[_socket close]; 关闭连接并销毁心跳。等一下,什么是心跳?这部分内容在下一个章节说明,暂时先可以理解为检测连接是否正常的一个机制。


- (void)sendData:(id)data {

        [self.socket send:data] ;

}

⑤、发送消息

- (void)sendData:(id)data 方法中通过调用[_socket send:data];方法发送消息。这个data可以是一个UTF8的字符串或者NSData对象。


- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {

    if (webSocket == self.socket) {

                NSLog(@"接收到后台下发的信息,在这解析。");

        }

}

⑥、通过代理方法来获取接收到的消息

当接收到信息时,会通过- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message代理方法回调。


按照常规,实现以上方法就已经实现了即时聊天的基本功能。但是,在现实的使用过程中,往往会出现一些特殊的情况需要处理。例如:1、在建立了链接后,如何确保客户端和服务端的之间的链接有效可用?2、虽然WebSocket通过握手建立了链接,但是在链接过程中可能遇到因为网络不好等的原因导致的连接中断情况,链接断了如何处理?3、在即时聊天项目中通常还要实现APSN即时推送功能,那服务器如何判断什么时候通过WebSocket发送消息,什么时候走APNs离线推送呢?

解决以上三个问题,就涉及到了三个webSocket的机制

1、心跳机制

用NSTimer每隔固定时间向服务器发一个心跳包,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。

//初始化心跳

- (void)initHeartBeat {

      dispatch_main_async_safe(^{

                    [self destoryHeartBeat];         //心跳设置为3分钟,NAT超时一般为5分钟

                    heartBeat = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];         //和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小

                    [[NSRunLoop currentRunLoop]addTimer:heartBeat forMode:NSRunLoopCommonModes];

        })

}

//取消心跳

- (void)destoryHeartBeat {

    dispatch_main_async_safe(^{

                if (heartBeat) {

                        if ([heartBeat respondsToSelector:@selector(isValid)]){

                                if ([heartBeat isValid]){

                                        [heartBeat invalidate];

                                        heartBeat = nil;

                                }

                        }

        }

    })

}

-(void)sentheart{

            //发送心跳 和后台可以约定发送什么内容  一般可以调用ping  这里根据后台的要求 发送了data给他

            [self sendData:@"heart"];

}

2、重连机制

重连机制比较好理解,值得注意的是当重连到一定次数仍然失败后要提示用户网络存在问题,就没必要再继续重连了。

- (void)reConnect {

            [self SRWebSocketClose];

                if (reConnectTime > 50) {

                // 重连50次都失败

                reConnectTime = 0;

                // 在这里弹出提示告知用户网络不好

                        return;

            }

          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

                    self.socket = nil;

                    [self SRWebSocketOpen];

            NSLog(@"重连");

            });

                    reConnectTime ++;

    }

3、pingpong机制

当服务端发出一个Ping,客户端没有在约定的时间内返回响应的ack,则认为客户端已经不在线,这时我们Server端会主动断开Scoket连接,并且改由APNS推送的方式发送消息。

//pingPong

- (void)ping{

    if (self.socket.readyState == SR_OPEN) {

                [self.socket sendPing:nil];

        }

}

//sendPing的时候,如果网络通的话,则会收到回调,但是必须保证ScoketOpen,否则会crash

- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {

        NSLog(@"收到pong回调");

}

至此,用SocketRocket建立一个聊天室所需的基本方法大概都列了一下。当然,中间仍有许多代码逻辑需要处理。这些内容会在仔细研读后继续整理出来。

写在最后

这篇文章只是我自己的学习笔记。第一次写简书,有点语无伦次,不好意思。文中的代码内容大多都是参考公司项目及网上的一些简书作者的文章。非常感谢这些博主及公司同事的无私分享。最后附上这些博主的原文。

iOS--SocketRocket框架的使用及测试服务器的搭建

socketRocket 封装,添加重连机制,block回调

iOS即时通讯,从入门到“放弃”?

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