iOS IM即时通讯小结:WebSocket

参考网站

即时通讯网

  • 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》

大牛博客
IM 即时通讯技术在多应用场景下的技术实现,以及性能调优

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

前言:要自己实现 IM 吗?

最近有项目涉及到聊天,Leader 决定要自己来实现 IM,不采用第三方的,像融云、环信等。其实,从心里我是拒绝的,因为作为一个IM的小白来说,一片空白,并且我们技术团队并没有很熟悉IM技术的人员,基本上算是从零开始,第三方的已经很成熟了,技术服务也很成熟完善了,相对于目前情况来说,对公司来说是最合适不过的了,时间金钱成本也是最合适的了,但是 Leader 已经决定了,要我们自己实现,以后还有项目中要用到,还想做一个 SDK 到时候开放,像 RongCloud 似的,呵呵,只是暂时说一下,先解决眼下的事情,也是一个锻炼学习的机会,第三方虽好,也不收费,但是在以后的某个时段,用户量达到一定量的时候,就需要 Money 了,毕竟都不是慈善机构,都要盈利的,有能力的话,最好是自己做了,定制型也强,想怎么玩就怎么玩,但这期间会遇到各种各样的问题困难,因为没有多少有价值的参考,很多东西都需要自己去摸索,需要浪费很多的时间精力。

用什么?

传输协议,TCP or UDP?

参考:
移动端IM/推送系统的协议选型:UDP还是TCP?

聊天协议?

协议名称 协议特点 第三方类库 优点 缺点
Socket 原生 Socket CocoaAsyncSocket 数据量小,性能高,扩展性比较强,比较知名的App如微信、QQ都基于此设计私有协议 开发量比较大,对开发者能力要求也比较高(没有发现连接时拼接参数的API)
WebSocket 基于 Socket 封装,传输通讯协议 SocketRocket(facebook)、Socket.IO-Client-Swift 同上 同上
XMPP 应用层的聊天协议 XMPPFramework 优点:协议开源,可拓展性强,在各个端(包括服务器)有各种语言的实现,开发者接入方便; 表现力弱、有太多冗余信息、流量大,
MQTT 同上 MQTTKit 协议简单,流量小,订阅+推送模式,适合滴滴、Uber实时获取位置 不适合于 IM 开发 ,适合用于推送,订阅
私有协议 一般都是基于 Socket 或 WebSocket 封装的协议 安全系数高,不容易被破解,主流 App 使用的方式

地址链接

CocoaAsyncSocket
SocketRocket
XMPPFramework
MQTTKit

Socket.IO-Client-Swift

Socket.io 功能非常强大,相对于上面的几个库,功能和 API 都这几个库要丰富完善的多;
Socket.io将 WebSocket 和轮询 (Polling)机制以及其它的实时通信方式封装成了通用的接口,并且在服务端实现了这些实时机制的相应代码。

注:
不过Socket.IO 对于 Swift 应该没有什么问题,OC 要做一些适配,还有版本的问题,主要是 Socket.IO 的SWIFT_VERSION 版本可能和当前工程的 SWIFT_VERSION 版本不匹配,或者是当前 Xcode 的版本已经不支持 Socket.IO 的 SWIFT_VERSION 等。不兼容的话,修改比较麻烦,OC要做一下适配,在之前我也有使用过,遇到过一些问题,在之前的文章中也简单介绍过。

最终就目前情况看,选择先使用 SocketRocket,功能和 API 比较简单,基于 SocketRocket 封装实现 Socket 的连接,监听,断开,重连等功能.

使用相关问题

1. WebSocket连接总是断开

  1. 连接总是断开,报这个错,code:1001,reason:Stream end encountered,wasClean:0,sendData:sendPing
    这个原因是因为,后台心跳检测一定时间内,服务端没有收到客户端发送的消息,就默认断开了与客户端的连接。

解决方法:

定时向服务单发送约定好的信息,心跳检测或者 sendPing 保证连接通畅(我自己理解的)。

- (void)dispatch_SourceTimerMethod
{
    //0.创建队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //1.创建GCD中的定时器
    /*
     第一个参数:创建source的类型 DISPATCH_SOURCE_TYPE_TIMER:定时器
     第二个参数:0
     第三个参数:0
     第四个参数:队列
     */
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    
    //2.设置时间等
    /*
     第一个参数:定时器对象
     第二个参数:DISPATCH_TIME_NOW 表示从现在开始计时
     第三个参数:间隔时间 GCD里面的时间最小单位为 纳秒
     第四个参数:精准度(表示允许的误差,0表示绝对精准)
     */
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, HeartTime * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    
    //3.要调用的任务
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"GCD-----%@",[NSThread currentThread]);
//        [self heartBeatData];
        [self sendPing];
    });
    
    //4.开始执行
    dispatch_resume(timer);
    
    //
    self.dispatch_SourceTimer = timer;
    
    // 需要取消的话:
//    dispatch_source_cancel(self.dispatch_SourceTimer);
//    此处注意一定要强引用定时器 ,否则定时器执行到 } 后将会被释放,无定时效果。
//    GCD定时器时间非常精准,最小的定时时间可以达到1纳秒,所以用在非常精确的定时场合。
}

/// PingPong
- (void)sendPing
{
    if (self.socket) {
        // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
        if(self.socket.readyState==SR_OPEN) {
            NSLog(@"************Ping**************");
            NSString *pingMsg = @"ping";
            NSData *pingData = [pingMsg dataUsingEncoding:NSUTF8StringEncoding];
            [self.socket sendPing:pingData];

//            [self.socket sendPing:nil];
        }else{
            NSLog(@"连接未打开");
        }
    }
}

崩溃
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid State: Cannot call send: until connection is open'

连接未打开时,发送数据时就会崩溃,发送数据前要判断 Socket 的连接状态。

你可能感兴趣的:(iOS IM即时通讯小结:WebSocket)