iOS webSocket 长链接的实践

针对SRWebSocket的再次封装, 已制作cocoapod库

git地址

本库是对SRWebSocket的再次封装, 经过一番折腾, 已经制作了cocoapod库, 可以直接执行 pod install

 pod 'NYLSRWebSocket'

封装包括断线重连: 断开后在网络可用的情况下重连5次, 5次失败利用定时器继续重连;

具体使用

连接
  // 连接
    [[NYLWebSocketManager shareManager] connectWebSocketWithSocketAddr:@"ws://10.10.22"];
连接成功的回调
// 连接成功
    [NYLWebSocketManager shareManager].wsConnectSuccessedBlock = ^{
        NSLog(@"连接接成功");
    };
发送消息
[[NYLWebSocketManager shareManager] sendData:@{}];
收到消息的回调

[NYLWebSocketManager shareManager].wsReceivedMsgBlock = ^(id  _Nonnull data) {
   		     
 };
连接失败回调
[NYLWebSocketManager shareManager].wsDidFailWithError = ^(NSError * _Nonnull  err) {
        
 };
关闭回调
[NYLWebSocketManager shareManager].wsDidCloseWithCodeAndReason = ^(NSInteger errCode, NSString * _Nonnull resson) {
        
    };
我的仓库地址
-> NYLSRWebSocket (0.0.1)
   针对SRWebSocket的封装
   pod 'NYLSRWebSocket', '~> 0.0.2'
   - Homepage: https://github.com/nieyinlong/NYLSRWebSocket
   - Source:   https://github.com/nieyinlong/NYLSRWebSocket.git
   - Versions: 0.0.2 [master repo]

核心代码

NYLWebSocketManager.h

//
//  NYLWebSocketManager.h
//  GoodDoctorForDoctor
//
//  Created by nyl on 2019/8/18.
//  Copyright © 2019 JamBo. All rights reserved.
//

#import <Foundation/Foundation.h>
@class SRWebSocket;

NS_ASSUME_NONNULL_BEGIN

@interface NYLWebSocketManager : NSObject

@property (nonatomic, copy) void(^wsConnectSuccessedBlock)(void);
@property (nonatomic, copy) void(^wsDidFailWithError)(NSError *err);
@property (nonatomic, copy) void(^wsDidCloseWithCodeAndReason)(NSInteger errCode, NSString *resson);
@property (nonatomic, strong) void (^wsReceivedMsgBlock)(id data);

@property (nonatomic, strong, readonly) SRWebSocket *socket;
@property (nonatomic, copy) NSString *socketAddr;

/**
 单例
 */
+ (NYLWebSocketManager *)shareManager;
- (void)connectWebSocketWithSocketAddr:(NSString *)addr;
- (void)sendData:(id)data;
- (void)closeWebSocketActively;
- (void)sendMsg:(NSString *)msg imgUrlStr:(NSString *)imgUrlStr detailID:(NSNumber *)detailID;

@end

NS_ASSUME_NONNULL_END

NYLWebSocketManager.m

//
//  NYLWebSocketManager.m
//  GoodDoctorForDoctor
//
//  Created by nyl on 2019/8/18.
//  Copyright © 2019 JamBo. All rights reserved.
//

#import "NYLWebSocketManager.h"
#import <SVProgressHUD/SVProgressHUD.h>
#import <AFNetworking/AFNetworking.h>
#import <SocketRocket/SRWebSocket.h>

@interface NYLWebSocketManager()<SRWebSocketDelegate>

@property (nonatomic, strong) SRWebSocket *socket;
/** 是否主动关闭长链接*/
@property (nonatomic, assign) BOOL isActivelyClose;
@property (nonatomic, strong) NSTimer *networkCheckTimer;
@property (nonatomic, assign) NSInteger reConnectCount;
@property (nonatomic, strong) NSTimer *reConnectTimer;

@end

@implementation NYLWebSocketManager

static NYLWebSocketManager *instance = nil;

+ (NYLWebSocketManager *)shareManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[NYLWebSocketManager alloc] init];
    });
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}

- (id)copyWithZone:(NSZone *)zone {
    return instance;
}

- (void)connectWebSocket
{
    self.isActivelyClose = NO;
    NSString *wsUrlStr = self.socketAddr;
    if (self.socketAddr.length == 0) {
        return;
    }
    self.socket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:wsUrlStr]];
    self.socket.delegate = self;
    [self.socket open];
}

- (void)connectWebSocketWithSocketAddr:(NSString *)addr
{
    self.socketAddr = addr;
    [self connectWebSocket];
}


- (void)closeWebSocketActively
{
    self.isActivelyClose = YES;
    self.reConnectCount = 0;
    [self destoryNetWorkCheckingTimer];
    [self endReConnectTimer];
    [self closeWebSocket];
}

- (void)closeWebSocket
{
    if (self.socket) {
        [self.socket close];
        self.socket = nil;
    }
}

- (void)reConnectWebSocket
{
    if (self.socket.readyState == SR_OPEN) { return; }
    if (self.reConnectCount <= 5) {
        [self connectWebSocket];
        self.reConnectCount++;
    } else {
        // 重连5次失败则用定时器进行重连
        if (self.reConnectTimer) {
            return;
        }
        self.reConnectTimer = [NSTimer scheduledTimerWithTimeInterval:4 target:self selector:@selector(actionReConnectTimer) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:self.reConnectTimer forMode:NSDefaultRunLoopMode];
    }
}


// 网络监测
- (void)startNetWorkStartChekingTimer
{
    [self destoryNetWorkCheckingTimer];
    if (self.networkCheckTimer) {
        return;
    }
    self.networkCheckTimer = [NSTimer scheduledTimerWithTimeInterval:1.3 target:self selector:@selector(actionNetWorkChecking) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.networkCheckTimer forMode:NSDefaultRunLoopMode];
}

- (void)destoryNetWorkCheckingTimer
{
    if (self.networkCheckTimer) {
        [self.networkCheckTimer invalidate];
        self.networkCheckTimer = nil;
    }
}

- (void)actionNetWorkChecking
{
    //有网络
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus != AFNetworkReachabilityStatusNotReachable) {
        //关闭网络检测定时器
        [self destoryNetWorkCheckingTimer];
        //开始重连
        [self reConnectWebSocket];
    } else {
       // NSLog(@"⚠️⚠️没有网络");
    }
}

- (void)endReConnectTimer
{
    if (self.reConnectTimer) {
        [self.reConnectTimer invalidate];
        self.reConnectTimer = nil;
    }
}

- (void)actionReConnectTimer
{
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus != AFNetworkReachabilityStatusNotReachable) {
        [self connectWebSocket];
    }
}


// 发送一条消息
- (void)sendMsg:(NSString *)msg imgUrlStr:(NSString *)imgUrlStr detailID:(NSNumber *)detailID
{
    NSDictionary *requestDic = @{@"text": msg, @"detailID": [NSString stringWithFormat:@"%@", detailID]};
    [self sendData:requestDic];
}


- (void)sendData:(id)data
{
    if (!data) { return; }
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
        [SVProgressHUD showErrorWithStatus:@"您的网络已断开!"];
        [self startNetWorkStartChekingTimer];
        return;
    }
    if (!self.socket || self.socket.readyState == SR_CLOSED || self.socket.readyState == SR_CLOSING) {
        [self reConnectWebSocket];
        return;
    }
    
    if (self.socket.readyState == SR_OPEN) {
        [SVProgressHUD show];
        [self.socket send:data];
    }
}

#pragma mark - SRWebSocketDelegate
-(void)webSocketDidOpen:(SRWebSocket *)webSocket
{
    [self endReConnectTimer];
    [self destoryNetWorkCheckingTimer];
    [SVProgressHUD showSuccessWithStatus:@"连接成功"];

    if (self.wsConnectSuccessedBlock) {
        self.wsConnectSuccessedBlock();
    }
}

-(void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
{
    NSLog(@"%@", message);
    if (self.wsReceivedMsgBlock) {
        self.wsReceivedMsgBlock(message);
    }
}

-(void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    [SVProgressHUD dismiss];
    if (self.wsDidFailWithError) {
        self.wsDidFailWithError(error);
    }
    
    if (self.isActivelyClose) {
        return;
    }
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
        [self startNetWorkStartChekingTimer];//开启网络检测
    } else {
        [self reConnectWebSocket];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
{
    [SVProgressHUD dismiss];
    if (self.wsDidCloseWithCodeAndReason) {
        self.wsDidCloseWithCodeAndReason(code, reason);
    }
    if (self.isActivelyClose) {
        return;
    }
    if (AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
        [self startNetWorkStartChekingTimer];//开启网络检测
    } else {
        [self reConnectWebSocket];
    }
}


@end

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值