WebSocket是什么
WebSocket是用于HTML的协议,可以在单个TCP连接进行全双工通信。不同于HTTP协议被动性,每次客户端先发起request,服务端再响应respon。而WebSocket是通过TCP有一个“握手”的连接后,客户端和服务端都可以向对方发送数据,类似socket的数据通信。WebSocket解决了HTTP非持久连接的问题,比通过轮询和长连接的方式更加高效、节省资源。
iOS WebSocket的使用
- 使用的框架:
- 封装一个单例:
@interface WebSocketHelper : NSObject+ (instancetype)helper;//开启连接- (void)connectWithURLString:(NSString *)urlString;//发送数据- (void)sendData:(id)data;//关闭连接- (void)closeWebSocket;@end#import "WebSocketHelper.h"#import "SocketRocket/SRWebSocket.h"@interface WebSocketHelper (){ NSTimer * _heartBeatTimer; NSTimeInterval _reConnectTime;}@property (nonatomic, strong) SRWebSocket *socket;@end@implementation WebSocketHelper+ (instancetype)helper { static WebSocketHelper *h = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ h = [[self alloc]init]; }); return h;}- (void)connectWithURLString:(NSString *)urlString { if (!urlString.length) { return; } if (self.socket) { return; } ///后台的websocket的地址 NSURLRequest *urlReq = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]; self.socket = [[SRWebSocket alloc]initWithURLRequest:urlReq]; self.socket.delegate = self; //开始连接 [self.socket open]; }#pragma mark - SRWebSocketDelegate- (void)webSocketDidOpen:(SRWebSocket *)webSocket { NSLog(@"连接成功"); _reConnectTime = 0; //开启心跳 心跳是发送pong的消息 我这里根据后台的要求发送data给后台 [self creatHeartBeat];}///连接失败- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error { NSLog(@"连接失败");}//被一方关闭连接了- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{ NSLog(@"连接断开了");}///接收服务器的pong消息- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(nullable NSData *)pongData{ NSString *reply = [[NSString alloc] initWithData:pongData encoding:NSUTF8StringEncoding]; NSLog(@"接收到pong消息:%@",reply); }- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message { //收到服务器发过来的数据 NSLog(@"接收到发过来的消息%@",message); }#pragma mark - custom methods- (void)closeWebSocket { if (self.socket){ //断开连接 [self.socket close]; self.socket = nil; //断开连接时销毁心跳 [self cancelHeartBeat]; }}//重连,当发现客户端和服务端断开连接时发起重连- (void)reConnect{ [self closeWebSocket]; //超过一分钟就不再重连 所以只会重连5次 2^5 = 64 if (_reConnectTime > 64) { return; } dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.socket open]; NSLog(@"重连"); }); //重连时间2的指数级增长 if (_reConnectTime == 0) { _reConnectTime = 2; }else{ _reConnectTime *= 2; }}//初始化心跳- (void)creatHeartBeat{ dispatch_async(dispatch_get_main_queue(), ^{ [self cancelHeartBeat]; __weak typeof(self) weakSelf = self; //心跳设置为3分钟,NAT超时一般为5分钟 self->_heartBeatTimer = [NSTimer scheduledTimerWithTimeInterval:3*60 repeats:YES block:^(NSTimer * _Nonnull timer) { NSLog(@"heart"); //发送心跳 [weakSelf sendData:@"heart"]; }]; [[NSRunLoop currentRunLoop]addTimer:self -> _heartBeatTimer forMode:NSRunLoopCommonModes]; }); }//取消心跳- (void)cancelHeartBeat{ dispatch_async(dispatch_get_main_queue(), ^{ if (self->_heartBeatTimer) { [self->_heartBeatTimer invalidate]; self->_heartBeatTimer = nil; } });}///发送数据- (void)sendData:(id)data { dispatch_queue_t queue = dispatch_queue_create("send.queue", NULL); __weak typeof(self) weakSelf = self; dispatch_async(queue, ^{ if (weakSelf.socket != nil) { // 只有 SR_OPEN 开启状态才能调 send 方法,不然要崩 if (weakSelf.socket.readyState == SR_OPEN) { NSError *error = nil; [weakSelf.socket sendData:data error:&error]; // 发送数据 } else if (weakSelf.socket.readyState == SR_CONNECTING) { NSLog(@"正在连接中"); [self reConnect]; } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) { // websocket 断开了,调用 reConnect 方法重连 [self reConnect]; } } else { NSLog(@"没网络,发送失败"); } });}@end复制代码
注意:调用的sendPing、sendData方法之前,必须判断当前scoket是否连接,如果不是连接状态,否则程序会crash。