UCWebSocketSever.m 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. //
  2. // UCWebSocketSever.m
  3. // wolfman
  4. //
  5. // Created by 张灿 on 2017/6/19.
  6. // Copyright © 2017年 shareSmile. All rights reserved.
  7. //
  8. #import "UCWebSocketSever.h"
  9. #import "UCSocketParmaModel.h"
  10. #import "SRSecurityPolicy.h"
  11. //通话已经取消(自己退出)
  12. @interface UCWebSocketSever()
  13. @property(nonatomic,strong)SRWebSocket* webSocket;
  14. @property(nonatomic,strong) dispatch_queue_t socketQueue;
  15. @property(nonatomic,copy)reconnectBlock reconnectblock;
  16. @property(nonatomic,assign)NSTimeInterval timeout;
  17. @property(nonatomic,strong)dispatch_source_t heartTimer;
  18. @property(nonatomic,assign)NSInteger reCount; //重连40次
  19. @end
  20. @implementation UCWebSocketSever
  21. +(instancetype)sharedWebSocketServer{
  22. static UCWebSocketSever* shareInstance = nil;
  23. static dispatch_once_t onceToken;
  24. dispatch_once(&onceToken, ^{
  25. shareInstance = [[super allocWithZone:NULL]init];
  26. shareInstance.socketQueue = dispatch_queue_create("com.caicaicp.webSocket", nil);
  27. shareInstance.reCount = 0;
  28. });
  29. return shareInstance;
  30. }
  31. + (instancetype)allocWithZone:(struct _NSZone *)zone{
  32. return [UCWebSocketSever sharedWebSocketServer];
  33. }
  34. - (id)copyWithZone:(struct _NSZone *)zone
  35. {
  36. return [UCWebSocketSever sharedWebSocketServer];
  37. }
  38. - (void)startConnentWebSocket:(NSInteger)reconn {
  39. if (!self.webSocket) {
  40. NSString* urlString;
  41. urlString = [NSString stringWithFormat:@"%@&reconnect=%zd",self.serveUrl,reconn];
  42. NSLog(@"webSocket网址--%@",urlString);
  43. self.webSocket = [[SRWebSocket alloc]
  44. initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] securityPolicy:[SRSecurityPolicy defaultPolicy]];
  45. self.webSocket.delegate = self;
  46. [self.webSocket open];
  47. }
  48. }
  49. - (void)removeDelegate{
  50. self.delegate = nil;
  51. }
  52. - (void)closeConnectWebSocket{
  53. [self.webSocket close];
  54. self.webSocket.delegate = nil;
  55. self.webSocket = nil;
  56. [self.timer invalidate]; // 将定时器从运行循环中移除,
  57. self.timer = nil;
  58. if (self.heartTimer) {
  59. dispatch_source_cancel(self.heartTimer);//删除GCD定时器
  60. self.heartTimer = nil;
  61. }
  62. }
  63. - (void)resetConnect{
  64. self.reCount++;
  65. [self closeConnectWebSocket];
  66. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  67. [self startConnentWebSocket:1];
  68. });
  69. }
  70. //连接成功回调
  71. - (void)webSocketDidOpen:(SRWebSocket *)webSocket {
  72. NSLog(@"连接成功");
  73. self.reCount = 0;
  74. NSLog(@"连接成功,可以立刻登录你公司后台的服务器了,还有开启心跳");
  75. if (!self.timer) {
  76. self.timer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(sendHeartMsg:) userInfo:nil repeats:YES];
  77. [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
  78. }
  79. if (!self.heartTimer) {
  80. [self timePaddingStart];
  81. }
  82. if (self.reconnectblock) {
  83. self.reconnectblock();
  84. self.reconnectblock = nil;
  85. }
  86. }
  87. //连接失败回调
  88. - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
  89. NSLog(@"连接失败,这里可以实现掉线自动重连,要注意以下几点");
  90. NSLog(@"1.判断当前网络环境,如果断网了就不要连了,等待网络到来,在发起重连");
  91. NSLog(@"2.判断调用层是否需要连接,例如用户都没在聊天界面,连接上去浪费流量");
  92. //add by leo 弱网断开警告
  93. if (self.delegate&& [self.delegate respondsToSelector:@selector(weakNetWorkWaring)]) {
  94. // [self.delegate weakNetWorkWaring];
  95. }
  96. // if (self.reCount<40) {
  97. [self resetConnect];
  98. // }
  99. }
  100. //关闭连接回调的代理
  101. - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
  102. // if (code==1001) { //服务器断开 自动重连
  103. NSLog(@"服务器断开连接--code%zd--reson%@",code,reason);
  104. if (self.webSocket) {
  105. // if (self.reCount<40) {
  106. [self resetConnect];
  107. // }
  108. }
  109. // }else if(code==1005){//客户端自己手动断开
  110. //
  111. // }
  112. }
  113. //接收消息
  114. - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
  115. // NSLog(@"接收消息");
  116. if ([message isKindOfClass:[NSString class]]) {
  117. NSString* str = (NSString*)message;
  118. // NSLog(@"STR=%@",str);
  119. NSArray* array = [str componentsSeparatedByString:@"@@"];
  120. for (NSString* tempStr in array) {
  121. if (![tempStr isEqualToString:@""]) {
  122. UCPacketBody *body = [[UCPacketBody alloc] initWithData:[tempStr dataUsingEncoding:NSUTF8StringEncoding]];
  123. if (self.delegate&& [self.delegate respondsToSelector:@selector(didRecvMessage:)]) {
  124. [self.delegate didRecvMessage:body];
  125. }
  126. NSDictionary* dict = [body.data mj_JSONObject];
  127. UCSocketParmaModel* param = [UCSocketParmaModel mj_objectWithKeyValues:dict];
  128. if ([param.method isEqualToString:@"heartbeat"]) {
  129. //重置时间
  130. self.timeout = 40;
  131. }
  132. }
  133. }
  134. }
  135. }
  136. - (void)sendData:(NSData*)data{
  137. @weakify(self);
  138. dispatch_async(self.socketQueue, ^{
  139. @strongify(self);
  140. if (self.webSocket != nil) {
  141. // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
  142. if (self.webSocket.readyState == SR_OPEN) {
  143. [self.webSocket sendData:data error:nil]; // 发送数据
  144. } else if (self.webSocket.readyState == SR_CONNECTING) {
  145. NSLog(@"正在连接中,重连后其他方法会去自动同步数据");
  146. // 每隔2秒检测一次 socket.readyState 状态,检测 10 次左右
  147. // 只要有一次状态是 SR_OPEN 的就调用 [ws.socket send:data] 发送数据
  148. // 如果 10 次都还是没连上的,那这个发送请求就丢失了,这种情况是服务器的问题了,小概率的
  149. } else if (self.webSocket.readyState == SR_CLOSING || self.webSocket.readyState == SR_CLOSED) {
  150. // websocket 断开了,调用 reConnect 方法重连
  151. [self reConnect:^{
  152. @strongify(self);
  153. [self.webSocket sendData:data error:nil];
  154. }];
  155. }
  156. } else {
  157. NSLog(@"webSocket已被清空");
  158. }
  159. });
  160. }
  161. //重新发送
  162. - (void)reConnect:(reconnectBlock)block{
  163. [self resetConnect];
  164. self.reconnectblock = block;
  165. }
  166. //发送心跳消息
  167. - (void)sendHeartMsg:(NSTimer*) theTimer
  168. {
  169. //发送心跳消息
  170. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  171. [dict setObject:@"heartbeat" forKey:@"method"];
  172. [dict setObject:@{@"room_id":self.roomId} forKey:@"data"];
  173. NSData* data = [dict mj_JSONData];
  174. if( [self.webSocket sendData:data error:nil]){
  175. NSLog(@"发送了心跳消息N");
  176. }
  177. }
  178. //收到心跳回复的倒计时
  179. - (void)timePaddingStart{
  180. self.timeout = 40;
  181. @weakify(self);
  182. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  183. dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
  184. self.heartTimer = timer;
  185. dispatch_source_set_timer(timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
  186. dispatch_source_set_event_handler(timer, ^{
  187. @strongify(self);
  188. if(self.timeout<=0){
  189. //没有收到心跳回调 重连if (self.webSocket.readyState!=SR_OPEN) {
  190. NSLog(@"没有收到回调,断开重连");
  191. // if (self.reCount<40) {
  192. [self resetConnect];
  193. // }
  194. }else{
  195. self.timeout--;
  196. }
  197. });
  198. dispatch_resume(timer);
  199. }
  200. @end