|
|
@@ -7,17 +7,15 @@
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
#import "GWebSocket.h"
|
|
|
-#import "SocketRocket/SRWebSocket.h"
|
|
|
-//#import "AFNetworking/AFNetworkReachabilityManager.h"
|
|
|
+#import <AFNetworking/AFNetworkReachabilityManager.h>
|
|
|
#import "GDBManager.h"
|
|
|
-//#import "AFNetworkReachabilityManager.h"
|
|
|
#import "ChatListStore.h"
|
|
|
#import "ChatsStore.h"
|
|
|
#import "WebRTCStore.h"
|
|
|
#import "UserNetApi.h"
|
|
|
#import "LoginStateManager.h"
|
|
|
|
|
|
-static int const kHeartbeatDuration = 1;
|
|
|
+static int const kHeartbeatDuration = 10;
|
|
|
static int const timeoutError = 5;
|
|
|
|
|
|
static NSString *ping = @"{\"code\":0}";
|
|
|
@@ -30,17 +28,14 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
|
|
|
@property (nonatomic,strong) NSString *serverIpString;
|
|
|
@property (nonatomic,strong) NSString *userid;
|
|
|
-
|
|
|
-@property (nonatomic,assign) BOOL autoReconnect;
|
|
|
-@property (nonatomic,assign) NSInteger pingCount;
|
|
|
-@property (nonatomic,assign) NSInteger reconnetCount;
|
|
|
-@property (nonatomic,assign) BOOL isFirstload;
|
|
|
@property (nonatomic,strong) NSString *UUID;
|
|
|
@end
|
|
|
|
|
|
|
|
|
@implementation GWebSocket
|
|
|
-
|
|
|
+{
|
|
|
+ BOOL _isReachable;
|
|
|
+}
|
|
|
+ (GWebSocket *_Nonnull)shareInstance{
|
|
|
static id gShareInstance = nil;
|
|
|
static dispatch_once_t onceToken;
|
|
|
@@ -52,32 +47,25 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
|
|
|
- (instancetype)init {
|
|
|
if (self = [super init]) {
|
|
|
- self.pingCount = 0;
|
|
|
- self.reconnetCount = 0;
|
|
|
NSUUID *uid = [NSUUID UUID];
|
|
|
_UUID=uid.UUIDString;
|
|
|
NSLog(@"_UUID:%@",_UUID);
|
|
|
+ [self startNetworkReachability];
|
|
|
+ [self startHeartbeat];
|
|
|
+ [self addObserver];
|
|
|
}
|
|
|
return self;
|
|
|
}
|
|
|
|
|
|
#pragma mark - Public -
|
|
|
- (void)connectWebSocket {
|
|
|
- self.autoReconnect = YES;
|
|
|
[self initWebSocket];
|
|
|
- [self startHeartbeat];
|
|
|
}
|
|
|
- (void)closeWebSocket {
|
|
|
- self.autoReconnect = NO;
|
|
|
// _UUID=nil;
|
|
|
[self close];
|
|
|
}
|
|
|
|
|
|
-#pragma mark 探测socket 状态
|
|
|
-- (void)chekWebSocket{
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
- (void)sendMsg:(NSString *)msg {
|
|
|
if (self.socket && self.socket.readyState == SR_OPEN) {
|
|
|
// 只有在socket状态为SR_OPEN 时,才可以发送消息
|
|
|
@@ -87,7 +75,7 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
}
|
|
|
else{
|
|
|
NSLog(@"socket--------不可用");
|
|
|
- [self reConnect];
|
|
|
+ [self reConnectSocket];
|
|
|
}
|
|
|
// NSLog(@"_UUID:%@",_UUID);
|
|
|
}
|
|
|
@@ -97,11 +85,6 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
#pragma mark -- WebSocket
|
|
|
//初始化 WebSocket
|
|
|
- (void)initWebSocket{
|
|
|
- if (_socket) {
|
|
|
- return;
|
|
|
- }
|
|
|
- self.isFirstload =YES;
|
|
|
-// [self destoryHeartbeat];
|
|
|
NSDictionary *userinfo =[UDManager.shareInstance getDDManager:dkuserinfo];
|
|
|
self.userid =userinfo[@"id"];
|
|
|
|
|
|
@@ -132,81 +115,76 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
}
|
|
|
|
|
|
#pragma mark - Heart Timer -
|
|
|
+
|
|
|
+- (void)addObserver {
|
|
|
+ // 进入后台
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
+ selector:@selector(appDidEnterBackground)
|
|
|
+ name:UIApplicationDidEnterBackgroundNotification
|
|
|
+ object:nil];
|
|
|
+
|
|
|
+ // 回到前台
|
|
|
+ [[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
+ selector:@selector(appWillEnterForeground)
|
|
|
+ name:UIApplicationWillEnterForegroundNotification
|
|
|
+ object:nil];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)appDidEnterBackground {
|
|
|
+ [self destoryHeartbeat];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)appWillEnterForeground {
|
|
|
+ [self startHeartbeat];
|
|
|
+ [self checkReconnectIfNeed];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
//保活机制 探测包
|
|
|
- (void)startHeartbeat {
|
|
|
- if(self.heatBeat){
|
|
|
- return;
|
|
|
- }
|
|
|
- self.heatBeat = [NSTimer scheduledTimerWithTimeInterval:kHeartbeatDuration target:self selector:@selector(heartbeatAction) userInfo:nil repeats:YES];
|
|
|
- [self.heatBeat setFireDate:[NSDate distantPast]];
|
|
|
- [[NSRunLoop currentRunLoop] addTimer:_heatBeat forMode:NSRunLoopCommonModes];
|
|
|
+ self.heatBeat = [NSTimer scheduledTimerWithTimeInterval:kHeartbeatDuration
|
|
|
+ target:self
|
|
|
+ selector:@selector(heartbeatAction)
|
|
|
+ userInfo:nil
|
|
|
+ repeats:YES];
|
|
|
+ [[NSRunLoop currentRunLoop] addTimer:self.heatBeat forMode:NSRunLoopCommonModes];
|
|
|
}
|
|
|
|
|
|
|
|
|
//断开连接时销毁心跳
|
|
|
- (void)destoryHeartbeat{
|
|
|
- if(self.heatBeat){
|
|
|
- [self.heatBeat invalidate];
|
|
|
- self.heatBeat = nil;
|
|
|
- }
|
|
|
+ [_heatBeat invalidate];
|
|
|
+ _heatBeat = nil;
|
|
|
}
|
|
|
|
|
|
// 发送心跳
|
|
|
- (void)heartbeatAction {
|
|
|
+ NSLog(@"XTWebSocket heartbeatAction readyState: %ld", self.socket.readyState);
|
|
|
|
|
|
- if (self.socket.readyState == SR_OPEN) {
|
|
|
-// NSLog(@"heartbeatAction1111");
|
|
|
- self.pingCount = self.pingCount+1;
|
|
|
- self.reconnetCount = self.reconnetCount+1;
|
|
|
- if(self.pingCount>5){//连续多次发送ping 没有收到回复,发起重连;
|
|
|
- [self.socket close];
|
|
|
- self.socket = nil;
|
|
|
- self.pingCount=0;
|
|
|
- [self reConnect];
|
|
|
- }
|
|
|
- if(self.pingCount>=3&&self.socket){
|
|
|
- [self sendPing];
|
|
|
- }
|
|
|
+ BOOL isLoggedIn = [LoginStateManager sharedManager].isLoggedIn;
|
|
|
+ if (!isLoggedIn) {
|
|
|
+ NSLog(@"XTWebSocket heartbeatAction not login!");
|
|
|
+ return;
|
|
|
}
|
|
|
- else{
|
|
|
-// NSLog(@"heartbeatAction222");
|
|
|
- self.pingCount = self.pingCount+1;
|
|
|
- self.reconnetCount = self.reconnetCount+1;
|
|
|
- if(self.pingCount>5){//连续多次发送ping 没有收到回复,发起重连;
|
|
|
- [self.socket close];
|
|
|
- self.socket = nil;
|
|
|
- self.pingCount=0;
|
|
|
- [self reConnect];
|
|
|
- }
|
|
|
+ switch (self.socket.readyState) {
|
|
|
+ case SR_CONNECTING:
|
|
|
+ break;
|
|
|
+ case SR_OPEN:
|
|
|
+ [self sendPing];
|
|
|
+ break;
|
|
|
+ case SR_CLOSING:
|
|
|
+ break;
|
|
|
+ case SR_CLOSED:
|
|
|
+ [self reConnectSocket];
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
//重连机制
|
|
|
-- (void)reConnect{
|
|
|
- if (!self.autoReconnect) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- self.socket = nil;
|
|
|
+- (void)reConnectSocket{
|
|
|
+ [self closeWebSocket];
|
|
|
[self initWebSocket];
|
|
|
-
|
|
|
-// NSLog(@"reConnect1111---------:%ld",(long)self.reconnetCount);
|
|
|
- if(self.reconnetCount>15){
|
|
|
- NSString *token = [UDManager.shareInstance getSDManager:gkeytoken];
|
|
|
- if([token isKindOfClass:[NSString class]]&&token.length>10){
|
|
|
- [UserNetApi getUserinfo:^(int code, NSDictionary * res) {
|
|
|
- NSNumber *gcode=res[@"code"];
|
|
|
- NSLog(@"gcode11");
|
|
|
- if([gcode intValue]==401){//token有效
|
|
|
- [self logoutAct];
|
|
|
- }
|
|
|
- } fail:^(NSError * _Nonnull error) {
|
|
|
- NSLog(@"11%@", error);
|
|
|
- }];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -220,16 +198,11 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
#pragma mark -- SRWebSocketDelegate
|
|
|
//收到服务器消息是回调
|
|
|
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message{
|
|
|
- //NSLog(@"----XTWebSocket didReceiveMessage:%@",message);
|
|
|
+ NSLog(@"----XTWebSocket didReceiveMessage:%@",message);
|
|
|
if ([message isKindOfClass:[NSString class]]) {
|
|
|
NSString *msg = (NSString *)message;
|
|
|
NSError *error;
|
|
|
- self.pingCount = 0;
|
|
|
- self.reconnetCount = 0;
|
|
|
if([msg isEqual:ping]){
|
|
|
- if(self.isFirstload){//第一次打开socket数据加载完成需要执行的
|
|
|
-
|
|
|
- }
|
|
|
return;
|
|
|
}
|
|
|
// NSLog(@"didReceiveMessage:%@",msg);
|
|
|
@@ -302,35 +275,29 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
- if(self.delegate){
|
|
|
- [self.delegate GWebSocketAction:message];
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//连接成功
|
|
|
- (void)webSocketDidOpen:(SRWebSocket *)webSocket{
|
|
|
- NSLog(@"-----XTWebSocket DidOpen");
|
|
|
-
|
|
|
- // 下面逻辑,根据业务情况处理
|
|
|
- if (self.socket != nil) {
|
|
|
- // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
|
|
|
- if (_socket.readyState == SR_OPEN) {
|
|
|
- //NSString *jsonString = @"{\"sid\": \"13b313a3-fea9-4e28-9e56-352458f7007f\"}";
|
|
|
- //[_socket sendString:jsonString error:nil]; //发送数据包
|
|
|
+ NSLog(@"-----XTWebSocket DidOpen: %ld", webSocket.readyState);
|
|
|
+ switch (webSocket.readyState) {
|
|
|
+ case SR_CONNECTING:
|
|
|
+ break;
|
|
|
+ case SR_OPEN:{
|
|
|
[self sendReady];
|
|
|
- } else if (_socket.readyState == SR_CONNECTING) {
|
|
|
- NSLog(@"正在连接中,重连后其他方法会去自动同步数据");
|
|
|
- // 每隔2秒检测一次 socket.readyState 状态,检测 10 次左右
|
|
|
- // 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
|
|
|
- // 如果 10 次都还是没连上的,那这个发送请求就丢失了,这种情况是服务器的问题了,小概率的
|
|
|
- // 代码有点长,我就写个逻辑在这里好了
|
|
|
-
|
|
|
- } else if (_socket.readyState == SR_CLOSING || _socket.readyState == SR_CLOSED) {
|
|
|
- // websocket 断开了,调用 reConnect 方法重连
|
|
|
- NSLog(@"websocket 断开了,调用 reConnect 方法重连");
|
|
|
- [self reConnect];
|
|
|
- }
|
|
|
+ if (![_heatBeat isValid]) {
|
|
|
+ [self destoryHeartbeat];
|
|
|
+ [self startHeartbeat];
|
|
|
+ }
|
|
|
+ }break;
|
|
|
+ case SR_CLOSING:
|
|
|
+ break;
|
|
|
+ case SR_CLOSED:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (self.delegate && [self.delegate respondsToSelector:@selector(onSocketConnectionStateChanged:)]) {
|
|
|
+ [self.delegate onSocketConnectionStateChanged:webSocket.readyState];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -340,23 +307,31 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
NSLog(@"XTWebSocket didFailWithError %@",error);
|
|
|
// 1.判断当前网络环境,如果断网了就不要连了,等待网络到来,在发起重连
|
|
|
// 2.判断调用层是否需要连接,例如用户都没在聊天界面,连接上去浪费流量
|
|
|
-
|
|
|
-// [self reConnect];
|
|
|
+ if (self.isReachable) {
|
|
|
+ [self reConnectSocket];
|
|
|
+ }
|
|
|
+ if (self.delegate && [self.delegate respondsToSelector:@selector(onSocketConnectionStateChanged:)]) {
|
|
|
+ [self.delegate onSocketConnectionStateChanged:webSocket.readyState];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//连接断开的回调
|
|
|
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{
|
|
|
NSLog(@"XTWebSocket Close code %ld reason %@",(long)code,reason);
|
|
|
+ if (self.delegate && [self.delegate respondsToSelector:@selector(onSocketConnectionStateChanged:)]) {
|
|
|
+ [self.delegate onSocketConnectionStateChanged:webSocket.readyState];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
|
|
|
- NSLog(@"XTWebSocket Pong");
|
|
|
+ NSString *string = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
|
|
|
+ NSLog(@"XTWebSocket Pong:%@", string);
|
|
|
}
|
|
|
|
|
|
#pragma mark - 其他 -
|
|
|
- (void)dealloc {
|
|
|
NSLog(@"LFC: dealloc: %@", self);
|
|
|
- [[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
+ [self close];
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -421,5 +396,41 @@ static NSString *redeady = @"{\"code\":1}";
|
|
|
}
|
|
|
|
|
|
|
|
|
+#pragma mark 检测网络状态
|
|
|
+-(void)startNetworkReachability {
|
|
|
+ AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
|
|
|
+ __weak typeof(manager) weakManager = manager;
|
|
|
+ [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
|
|
|
+ BOOL isReachable = weakManager.isReachable;
|
|
|
+ self->_isReachable = isReachable;
|
|
|
+ NSLog(@"XTWebSocket ReachabilityStatusChange: %d", isReachable);
|
|
|
+ if (isReachable) {
|
|
|
+ [self checkReconnectIfNeed];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ [manager startMonitoring];
|
|
|
+}
|
|
|
+
|
|
|
+- (BOOL)isReachable {
|
|
|
+ return _isReachable;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)checkReconnectIfNeed {
|
|
|
+ NSLog(@"XTWebSocket checkReconnectIfNeed readyState: %ld", self.socket.readyState);
|
|
|
+ switch (self.socket.readyState) {
|
|
|
+ case SR_CONNECTING:
|
|
|
+ break;
|
|
|
+ case SR_OPEN:
|
|
|
+ break;
|
|
|
+ case SR_CLOSING:
|
|
|
+ break;
|
|
|
+ case SR_CLOSED:{
|
|
|
+ if (self.isReachable) {
|
|
|
+ [self reConnectSocket];
|
|
|
+ }
|
|
|
+ }break;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
@end
|