美文网首页iOS开发资料收集大公司框架解析iOS 网络和线程
socketRocket 封装,添加重连机制,block回调

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

作者: gitKong | 来源:发表于2016-09-23 14:47 被阅读2746次

    一、简单介绍

    SocketRocket是一个WebSocket客户端(WebSocket是适用于Web应用的下一代全双工通讯协议,被成为“Web的TCP”,它实现了浏览器与服务器的双向通信),采用Object-C编写。SocketRocket遵循最新的WebSocket规范RFC 6455

    这里是开发者描述的其一些特性/设计:

    支持TLS (wss)。
    使用NSStream/CFNetworking。
    使用ARC。
    采用并行架构。大部分的工作由后端的工作队列(worker queues)完成。
    基于委托编程。

    SocketRocket支持iOS 4.x系统(应该也可以运行于OS X),不需要任何UI包依赖。详细信息可以查看此文介绍

    socketRocket 传送门

    二、如何使用

    • socketRocket 支持pod,因此直接添加然后install,文件不多喔~

    Paste_Image.png
    • 简单使用socketRocket实现通信的话,只需要用那么几个API就行了

    1.创建一个请求:(有多种方法)

    - (id)initWithURLRequest:(NSURLRequest *)request;
    

    2.遵守并指定代理

    @property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
    

    3.打开连接加载请求

    - (void)open;
    

    4.关闭连接

    - (void)close;
    

    5.发送消息

    // Send a UTF8 String or Data.
    - (void)send:(id)data;
    // Send Data (can be nil) in a ping message.
    - (void)sendPing:(NSData *)data;
    

    6.监听socketRocket是通过代理方法来实现的

    @protocol SRWebSocketDelegate <NSObject>
    // message will either be an NSString if the server is using text
    // or NSData if the server is using binary.
    - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
    @optional
    - (void)webSocketDidOpen:(SRWebSocket *)webSocket;
    - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
    - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
    - (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;
    // Return YES to convert messages sent as Text to an NSString. Return NO to skip NSData -> NSString conversion for Text messages. Defaults to YES.
    - (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket;
    
    • 注意:发送的参数必须跟后台商量,保持一致才能发送,不然一发送就自动关闭连接的

    三、封装隔离

    • 为什么要封装

    • 我就按上面的6个步骤就可以实现通信了,不用考虑太多的逻辑处理,但我还是觉得有点麻烦,我希望一句代码就搞定,使用代理就实现不了。

    • 第三方框架必须要封装隔离,不然Facebook突然改了这个框架的API,那么你项目多次使用的话,改动工作量就非常大了。

    • 我需要它有个重连机制,如果连接失败或者系统异常原因导致连接关闭的话,它会自动重连,如果是用户手动关闭,则不需要重连,直到下次重新打开。

    • 封装思路

    • 需要单例工具类,管理socket的状态,当然状态是不允许外界修改,因此是readonly

    • 对外提供超时重连的时间,允许外界修改

    • 对外提供开启连接方法,使用block进行回调,不使用代理,实现一句代码创建并监听

    • 有开启必须有关闭连接的方法,同样使用block回调,告诉调用者关闭的状态码以及原因

    • 当然需要一个发送方法,参数模仿框架,传id类型就行

    • 封装后的API(.h文件)

    自定义的枚举,socket状态,比框架多一个枚举是用户关闭

    /**
     *  @author 孔凡列, 16-09-21 07:09:52
     *
     *  socket状态
     */
    typedef NS_ENUM(NSInteger,FLSocketStatus){
        FLSocketStatusConnected,// 已连接
        FLSocketStatusFailed,// 失败
        FLSocketStatusClosedByServer,// 系统关闭
        FLSocketStatusClosedByUser,// 用户关闭
        FLSocketStatusReceived// 接收消息
    };
    /**
     *  @author 孔凡列, 16-09-21 07:09:52
     *
     *  消息类型
     */
    typedef NS_ENUM(NSInteger,FLSocketReceiveType){
        FLSocketReceiveTypeForMessage,
        FLSocketReceiveTypeForPong
    };
    
    

    连接回调,成功连接后执行

    
    /**
     *  @author 孔凡列, 16-09-21 08:09:06
     *
     *  连接回调
     */
    @property (nonatomic,copy)FLSocketDidConnectBlock connect;
    
    

    接收到socket消息的时候就会执行

    /**
     *  @author 孔凡列, 16-09-21 08:09:06
     *
     *  接收消息回调
     */
    @property (nonatomic,copy)FLSocketDidReceiveBlock receive;
    
    

    连接或发送失败会执行

    /**
     *  @author 孔凡列, 16-09-21 08:09:06
     *
     *  失败回调
     */
    @property (nonatomic,copy)FLSocketDidFailBlock failure;
    
    

    用户手动关闭或者系统关闭的时候会调用

    /**
     *  @author 孔凡列, 16-09-21 08:09:06
     *
     *  关闭回调
     */
    @property (nonatomic,copy)FLSocketDidCloseBlock close;
    
    

    socket状态,一共有5个状态

    /**
     *  @author 孔凡列, 16-09-21 08:09:28
     *
     *  当前的socket状态
     */
    @property (nonatomic,assign,readonly)FLSocketStatus fl_socketStatus;
    
    

    超时重连时间,默认一秒重连(框架没有,自己添加的)

    /**
     *  @author 孔凡列, 16-09-21 08:09:40
     *
     *  超时重连时间,默认1秒
     */
    @property (nonatomic,assign)NSTimeInterval overtime;
    

    超时重连次数,默认5次(框架没有,自己添加的)

    /**
     *  @author Clarence
     *
     *  重连次数,默认5次
     */
    @property (nonatomic, assign)NSUInteger reconnectCount;
    

    单例创建管理类,项目中唯一,方便管理

    /**
     *  @author 孔凡列, 16-09-21 08:09:06
     *
     *  单例调用
     */
    + (instancetype)shareManager;
    

    开启socket,block监听

    /**
     *  @author 孔凡列, 16-09-21 08:09:16
     *
     *  开启socket
     *
     *  @param urlStr  服务器地址
     *  @param connect 连接成功回调
     *  @param receive 接收消息回调
     *  @param failure 失败回调
     */
    - (void)fl_open:(NSString *)urlStr connect:(FLSocketDidConnectBlock)connect receive:(FLSocketDidReceiveBlock)receive failure:(FLSocketDidFailBlock)failure;
    

    关闭socket,有两个状态,一个是用户关闭,一个是系统关闭

    /**
     *  @author 孔凡列, 16-09-21 08:09:06
     *
     *  关闭socket
     *
     *  @param close 关闭回调
     */
    - (void)fl_close:(FLSocketDidCloseBlock)close;
    

    发送消息,可发送NSString 或者 NSData

    /**
     *  @author 孔凡列, 16-09-21 08:09:25
     *
     *  发送消息,NSString 或者 NSData
     *
     *  @param data Send a UTF8 String or Data.
     */
    - (void)fl_send:(id)data;
    
    

    四、调用

    1、开启连接并监听

       NSString *url = @"服务器给你的地址";
       [[FLSocketManager shareManager] fl_open:url connect:^{
            NSLog(@"成功连接");
        } receive:^(id message, FLSocketReceiveType type) {
            if (type == FLSocketReceiveTypeForMessage) {
                NSLog(@"接收 类型1--%@",message);
            }
            else if (type == FLSocketReceiveTypeForPong){
                NSLog(@"接收 类型2--%@",message);
            }
        } failure:^(NSError *error) {
            NSLog(@"连接失败");
        }];
    

    2、发送消息

    [[FLSocketManager shareManager] fl_send:@"hello world"];
    

    3、关闭连接

    [[FLSocketManager shareManager] fl_close:^(NSInteger code, NSString *reason, BOOL wasClean) {
            NSLog(@"code = %zd,reason = %@",code,reason);
        }];
    

    五、总结

    • 使用block回调,用法只需要三步,监听都在同一个方法里面,方便管理,关键是看起来简单,用起来爽,而且不怕框架API修改

    • 有重连机制,连接失败或者系统异常原因导致关闭的就会自动重连,默认一秒就重连,如果调用者手动关闭就不重连,有最大重连次数,可自定义,默认5次

    • 实现部分的代码就拷贝上来了,喜欢的话就去clone吧,demo没有给服务器地址,实测没问题的

    • 一般socket开启后就不用关闭,此时作者封装的这个block是单例对象的,因此如果另一个控制器监听了接收block,那么前一个控制器就没办法监听接收,建议大家使用通知去实现,只需要在一个控制器去做监听,然后发通知,其他控制器监听这个通知就行,这样就可以实现整个项目多个控制器都能同时监听socket改变

    gitHub地址 欢迎大家关注我,随时发干货,喜欢就给个star && like,有问题留言哟~~~

    相关文章

      网友评论

      • vihong丶:你好,请问下这个框架怎么做ssl认证?
      • fa1f969a6a42:作者您好,我用了您的这个封装,为什么10秒钟就收不到消息了,既没进入后台,也无任何提示。
        我用这个收不到消息的设备发送消息提示:Closed Reason:Stream end encountered code = 1001
        fa1f969a6a42:@gitKong 我再问一下,你们这个心跳包,我怎么没看到哪里有发送呢。。
        fa1f969a6a42:貌似是没发心跳包,被后台踢出去了。
        gitKong:@摧毁asy_111d socket断了吧
      • love断鸿:请问下如果用你封装的这个tool https适配 需要我们做什么吗?
        gitKong:@love断鸿 可以这样,先请求服务端,成功后开启socket
        love断鸿:@gitKong 我现在遇到个问题, 在连接的时候就要向服务器穿参数 该怎么办啊
        gitKong:不需要
      • 你猜哈哈:我们现在在做一个类似于客服的聊天。后台让我们APP端先用一个总的websocket来监听用户上线,如果用户上线就创建一个websocket,有10个用户就得创建10个websocket,如何来监听处理每个websocket的消息,我现在一点思路都没有
        gitKong:@你猜哈哈 相当于回话嘛,在各自的回话里面监听处理
      • 玉思盈蝶:请问这个可以传输文件么?比如图片啥的
        gitKong:@玉思盈蝶 不太清楚。。。你跟后端对调一下就好了
        玉思盈蝶:@gitKong 我图片转data,返回是:Closed Reason:(null) code = 1002
        知道为什么么?
        gitKong:@玉思盈蝶 data
      • 可了个可:你好,请问
        在didCloseWithCode回调方法中重连的判断条件是reason,这个是不是不妥?
        因为我发现不管是服务端关闭连接,还是自己主动close,回调结果都是如下,
        code:1001,reason:Stream end encountered,wasClean:0
        并不能区分
        gitKong:@keke 给你个解决办法,你客户端用一个字段存储一个flag,区分是客户端关闭还是服务端关闭
        可了个可:@gitKong 如果网络断开,或者信号不好,会有didFailWithError,这肯定是要重连的。
        但是close的话我目前项目中会有两种情况
        1.一种是服务端某种原因给关掉了
        2.另一种就是自己调用的close方法
        但是得到的回调方法,reason都是一样的,我只是想在第1种情况时候触发重连。
        gitKong:@keke 如果是发生错误而关闭的就区分了,服务端关闭和客户端关闭都是主动关闭

      本文标题:socketRocket 封装,添加重连机制,block回调

      本文链接:https://www.haomeiwen.com/subject/wqutyttx.html