美文网首页OC-开发案例收集
iOS Websocket使用指南

iOS Websocket使用指南

作者: 阿木摄影 | 来源:发表于2019-04-25 20:55 被阅读0次

    文章原创如需转载,请注明出处"本文首发于一之笔";

    背景介绍

    在消控项目中,实时监测,电气监管未来可能会根据业务,实行主动推送数据,APP接收到WSS的推送数据,实时更新页面;

    框架介绍

    facebook/SocketRocket

    • Facebook开源的可用于iOS,Mac Os系统的socket库
    • 支持自动管理socket的生命周期;
    • 支持HTTP,HTTPS;
    • 发送 ping,响应 pong 事件;

    如何使用

    • 需要跟服务端约定心跳,并且约定发送的数据,即需要每隔几秒告诉服务端,客户端在线,并且有新的数据推给客户端;

    • 销毁心跳,当页面销毁后,销毁心跳,断开Websocket;

    tips如果数据量过大,可以采用 Zip 压缩数据;

    Pod导入

    pod 'SocketRocket'
    

    关键代码

    <SRWebSocketDelegate>//遵循协议
    {
    NSTimer * heartBeat;//心跳包
    }
    @property (nonatomic,strong) SRWebSocket *socket;//socket
    
    #pragma mark - Socket
    - (void)setUpMarkertSocket {
    self.socket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"wss://api.test.com/ws"]]];
    NSLog(@"请求的websocket地址:%@",self.socket.url.absoluteString);
    self.socket.delegate = self;
    [self.socket open];
    }
    #pragma mark - SRWebSocketDelegate
    - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    if (webSocket == self.socket) {
    //接收到推送的新数据message,可以是json,可以是data等
    }
    }
    - (void)webSocketDidOpen:(SRWebSocket *)webSocket {
        NSLog(@"socket连接成功");
        [self initHeartBeat];//初始化心跳
    }
    - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
        NSLog(@"socket连接失败:%@",error);
    }
    - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
        NSLog(@"socket连接关闭:%@",reason);
    }
    - (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
        NSData * jsonData = [LFCGzipUtility ungzipData:pongPayload];
        id resObj = [NSJSONSerialization JSONObjectWithData:jsonData     options:NSJSONReadingMutableContainers error:nil];
        NSLog(@"socket连接接收pong:%@",resObj);
    }
    - (void)checkHeartWithPongData:(NSMutableDictionary *)pongData {
        [self sendScoketParams:pongData];
    }
    - (void)sendRequestParams {
    //发送心跳 和后台可以约定发送什么内容  一般可以调用ping  我这里根据后台的要求 发送了data给他
    //在成功后需要做的操作。。。
        NSMutableDictionary* param = @{
        @"sub":[NSString stringWithFormat: @"test"],//
        @"id": @"id10" //行情
        }.mutableCopy;
        [self sendScoketParams:param];
    }
    - (void)sendScoketParams:(NSMutableDictionary *)param {
        NSString* dataStr = [ToolUtil dictionaryConvertToJsonData:param];
        @weakify(self);
        dispatch_queue_t queue =  dispatch_queue_create("zy", NULL);
        dispatch_async(queue, ^{
        @strongify(self);
        if (self.socket != nil) {
    // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
        if (self.socket.readyState == SR_OPEN) {
        [self.socket send:dataStr];    // 发送数据
      }   else if (self.socket.readyState == SR_CONNECTING) {
        NSLog(@"正在连接中,重连后其他方法会去自动同步数据");
    // 每隔2秒检测一次 socket.readyState 状态,检测 10 次左右
    // 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
    // 如果 10 次都还是没连上的,那这个发送请求就丢失了,这种情况是服务器的问题了,小概率的
    // 代码有点长,我就写个逻辑在这里好了
        // [self reConnect];
      } else if (self.socket.readyState == SR_CLOSING || self.socket.readyState == SR_CLOSED)   {
    // websocket 断开了,调用 reConnect 方法重连
      NSLog(@"重连");
        [self setUpMarkertSocket];
      }
     } else {
    NSLog(@"没网络,发送失败,一旦断网 socket 会被我设置 nil 的");
    NSLog(@"其实最好是发送前判断一下网络状态比较好,我写的有点晦涩,socket==nil来表示断网");
            }
      });
    }
    

    心跳管理

    //初始化心跳
    - (void)initHeartBeat {
        dispatch_main_async_safe(^{
        [self destoryHeartBeat];
        [self sendRequestParams];
    //心跳设置为3分钟,NAT超时一般为5分钟
        heartBeat = [NSTimer timerWithTimeInterval:10 target:self     selector:@selector(sendRequestParams) 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;
                        }
                }
          }
      })
    }
    

    使用遇到问题,欢迎留言讨论;

    相关文章

      网友评论

        本文标题:iOS Websocket使用指南

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