iOS websocket

摘要:
iOSwebsocket最近在开发一个直播应用,需要用到弹幕功能,后台说要用websocket来实现,所以学习了一下一、RocketSocket搜索了一下发现,用的最多的还是Facebook的RocketSocket库,虽然已经停止维护了,但是还能使用。_webSocket){NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:[NSURLURLWithString:SOCKET_SERVER_URL]];[requestsetValue:[NSStringgetAccessTokenString]forHTTPHeaderField:@"Authorization"];_webSocket=[[SRWebSocketalloc]initWithURLRequest:request];_webSocket.delegate=self;}return_webSocket;}打开socket,开始连接-openWebSocket{if{return;}[self.webSocketopen];}监听消息-subscribeNewMessage{NSString*sendString=[NSStringstringWithFormat:@"SUBSCRIBEdestination:%@id:%@",SOCKET_SEND_URL,@"sub-0"];NSLog;NSData*data=[sendStringdataUsingEncoding:NSUTF8StringEncoding];[self.webSocketsend:data];}发送消息-sendMessage:message{if{if{NSString*sendString=[NSStringstringWithFormat:@"SENDAuthorization:%@destination:%@%@",[NSStringgetAccessTokenString],SOCKET_SEND_URL,[NSStringgetJsonStringOfDictionary:message]];NSLog;NSData*data=[sendStringdataUsingEncoding:NSUTF8StringEncoding];[self.webSocketsend:data];}}else{[selfopenWebSocket];}}SRWebSocketDelegate,代理事件#pragmamark-SRWebSocketDelegate-webSocketDidOpen:webSocket{NSLog;if{self.reopenCount=0;//[selfstartHeartBeat];//[selfsubscribeNewMessage];}}-webSocket:webSocketdidFailWithError:error{NSLog;if{[selfreopenWebSocket];}}-webSocket:webSocketdidCloseWithCode:codereason:reasonwasClean:wasClean{NSLog;if{[selfcloseWebSocket];}}-webSocket:webSocketdidReceivePong:pongPayload{NSLog;if{}}-webSocket:webSocketdidReceiveMessage:message{NSLog;if{if{self.receiveMessage;}}}心跳和重连因为封装的比较简单,代码看起来很明了,但是有些地方需要自己完善。我这里主要加了心跳和重连机制。

iOS websocket

最近在开发一个直播应用,需要用到弹幕功能,后台说要用websocket来实现,所以学习了一下

一、 RocketSocket
搜索了一下发现,用的最多的还是Facebook的RocketSocket库,虽然已经停止维护了,但是还能使用。

  1. 创建socket

    - (SRWebSocket *)webSocket {
        if (!_webSocket) {
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:SOCKET_SERVER_URL]];
            [request setValue:[NSString getAccessTokenString] forHTTPHeaderField:@"Authorization"];
            _webSocket = [[SRWebSocket alloc] initWithURLRequest:request];
            _webSocket.delegate = self;
        }
        return _webSocket;
    }
    
  2. 打开socket,开始连接

    - (void)openWebSocket {
        if (self.webSocket.readyState == SR_OPEN) {
            return;
        }
        [self.webSocket open];
    }
    
  3. 监听消息

    - (void)subscribeNewMessage {
        NSString *sendString = [NSString stringWithFormat:@"SUBSCRIBE
    destination: %@
    id: %@
    
    ", SOCKET_SEND_URL(@(self.channelId)), @"sub-0"];
        NSLog(@"%@", sendString);
        NSData *data = [sendString dataUsingEncoding:NSUTF8StringEncoding];
        [self.webSocket send:data];
    }
    
  4. 发送消息

    - (void)sendMessage:(NSDictionary *)message {
        if (self.webSocket) {
            if (self.webSocket.readyState == SR_OPEN) {
                NSString *sendString = [NSString stringWithFormat:@"SEND
    Authorization: %@
    destination: %@
    
    %@", [NSString getAccessTokenString], SOCKET_SEND_URL(message[@"accountId"]), [NSString getJsonStringOfDictionary:message]];
                NSLog(@"sendMessage :%@", sendString);
                NSData *data = [sendString dataUsingEncoding:NSUTF8StringEncoding];
                [self.webSocket send:data];
            }
        } else {
            [self openWebSocket];
        }
    }
    
  5. SRWebSocketDelegate, 代理事件

    #pragma mark - SRWebSocketDelegate
    
    - (void)webSocketDidOpen:(SRWebSocket *)webSocket {
        NSLog(@"webSocketDidOpen");
        if ([webSocket isEqual:self.webSocket]) {
            self.reopenCount = 0;
    //        [self startHeartBeat];
    //        [self subscribeNewMessage];
        }
    }
    
    - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
        NSLog(@"didFailWithError: %@", error);
        if ([webSocket isEqual:self.webSocket]) {
            [self reopenWebSocket];
        }
    }
    
    - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
        NSLog(@"didCloseWithCode: %ld, %@, %d", (long)code, reason, wasClean);
        if ([webSocket isEqual:self.webSocket]) {
            [self closeWebSocket];
        }
    }
    
    - (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
        NSLog(@"didReceivePong: %@", pongPayload);
        if ([webSocket isEqual:self.webSocket]) {
    
        }
    }
    
    - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
        NSLog(@"didReceiveMessage: %@", message);
        if ([webSocket isEqual:self.webSocket]) {
            if (self.receiveMessage) {
                self.receiveMessage(message);
            }
        }
    }
    
  6. 心跳和重连
    因为封装的比较简单,代码看起来很明了,但是有些地方需要自己完善。我这里主要加了心跳和重连机制。

    - (NSTimer *)heartBeatTimer {
        if (!_heartBeatTimer) {
            _heartBeatTimer = [NSTimer timerWithTimeInterval:heartBeatTimeInterval target:self selector:@selector(sendPing) userInfo:nil repeats:YES];
        }
        return _heartBeatTimer;
    }
    
    - (void)startHeartBeat {
        if (!_heartBeatTimer) {
            [[NSRunLoop currentRunLoop] addTimer:self.heartBeatTimer forMode:NSRunLoopCommonModes];
    //        [[NSRunLoop currentRunLoop] run];//子线程需要手动启动runloop
        }
    }
    
    - (void)stopHeartBeat {
        if (_heartBeatTimer) {
            [self.heartBeatTimer invalidate];
            self.heartBeatTimer = nil;
        }
    }
    
    - (void)sendPing {
        if (self.webSocket.readyState == SR_OPEN) {
            [self.webSocket sendPing:nil];
        }
    }
    
    - (void)reopenWebSocket {
        [self closeWebSocket];
        if (self.reopenCount >= maxReopenCount) {
            if (self.reconnectFailed) {
                self.reconnectFailed();
            }
            return;
        }
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            [self openWebSocket];
            self.reopenCount ++;
        });
    }
    

二、 WebsocketStompKit
用rocketsocket写完之后,开始和后端联调,发现连接成功之后后端根本发现不了,连log都没有。对比着js中的方法,发现有用到Stomp,看源码挺简单的,只是把数据封装了一层,所以我就照着写了,在调试的时候还是不行。然后就去网上搜索iOS支持stomp协议的websocket库,就找到了这个WebsocketStompKit

这个库封装的更好一些,用起来很方便。

  1. 创建client

    - (STOMPClient *)webSocket {
        if (!_webSocket) {
            NSURL *url = [NSURL URLWithString:SOCKET_SERVER_URL];
            NSDictionary *headers = @{
                @"Authorization": [NSString getAccessTokenString],
            };
            _webSocket = [[STOMPClient alloc] initWithURL:url webSocketHeaders:headers useHeartbeat:YES];
            _webSocket.delegate = self;
        }
        return _webSocket;
    }
    
  2. 打开socket,开始连接

    - (void)openWebSocket {
        NSDictionary *headers = @{
            @"Authorization": [NSString getAccessTokenString],
        };
        [self.webSocket connectWithHeaders:headers completionHandler:^(STOMPFrame *connectedFrame, NSError *error) {
            NSLog(@"connectWithHeaders: %@---%@", connectedFrame, error);
            if (error) {//连接失败提示
                dispatch_async(dispatch_get_main_queue(), ^{
                    
                });
            } else {//连接成功订阅消息
                [self subscribeNewMessage];
            }
        }];
    }
    
  3. 订阅消息

    - (void)subscribeNewMessage {
        [self.webSocket subscribeTo:[NSString stringWithFormat:@"/topic/222.%lld", self.channelId] headers:@{} messageHandler:^(STOMPMessage *message) {
            NSLog(@"receive message: %@", message);
            if (self.receiveMessage) {
                self.receiveMessage([NSString getDictionaryFromJsonString:message.body]);
            }
        }];
    }
    
  4. 发送消息

    - (void)sendMessage:(NSDictionary *)message {
        NSDictionary *headers = @{
            @"Authorization": [NSString getAccessTokenString],
        };
        [self.webSocket sendTo:SOCKET_SEND_URL(message[@"accountId"]) headers:headers body:[NSString getJsonStringOfDictionary:message]];
    }
    

使用过程中又崩溃的情况,我这里修改了几个地方,详情请见我的Fork

比较上面的两种库,回调方式分别用来delegate和block,看起来使用delegate的方式容易对整个流程有把控,每一步都有对应的方法,写起来稍微麻烦一些,但是容易理解;使用block的方式写起来很简单,但是理解起来稍显困难,不过更容易集中注意力到事件及回调上,其他过程可忽略。我倾向于前者。

参考:
iOS WebSocket长连接
WebSocket Demo
WebsocketStompKit使用

免责声明:文章转载自《iOS websocket》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux基础知识(一)ffmpeg综合应用示例(三)——安卓手机摄像头编码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

UITableView总结

性能优化 /** * 每当有一个cell要进入视野范围内,就会调用一次 */ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"wine...

MQTT-Client-FrameWork使用整理

作者: wbl MQTT MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和制动器(比如通过Twitter让房屋联网)的通信协议 MQTT特点 MQTT协议是为大量计算...

IOS管理文件和目录

  1、常见的NSFileManager文件方法 -(NSData *)contentsAtPath:path  //从一个文件读取数据 -(BOOL)createFileAtPath: path contents:(NSData *)data attributes:attr  //向一个文件写入数据 -(BOOL)removeItemAtPath:pa...

iOS https请求 NSURLSessionDataTask

// //  YKSHttpsRequest.m //  YKShareSdkDemo // //  Created by qingyun on 22/05/2017. //  Copyright © 2017 qingjoin. All rights reserved. // #import "YKSHttpsRequest.h" @implementa...

js(javascript)与ios(Objective-C)相互通信交互

随着苹果SDK的不断升级,越来越多的新特性增加了进来,本文主要讲述从iOS6至今,Native与JavaScript的交互方法 一、UIWebview && iframe && JavaScript  <=iOS6 iOS6原生没有提供js直接调用Objective-C的方式,只能通过UIWebView的UIWebVi...

WebSocket实现前后端通讯

WebSocket实现前后端通讯         长安如梦里,何日是归期。   简介:我们上线了一个商城项目,移交运营团队使用之后,他们要求商城有新订单来的时候同时加上声音提示,让她们可以及时知道有单来了。我这边想了想,这个需求是在后端完成还是前端完成,但是仔细一想,无论是在前端还是后端完成都一样,需求注定甩不出去了,因为这个商城的后台管理没有前端工程师,...