




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在iOS中实现WebSocket长链接
今天就跟大家聊聊有关怎么在iOS中实现WebSocket长链接,可能很多人都不太了解,为了让大家更加了解,在下给大家总结了以下内容,希望大家根据这篇文章可以有所收获。WebSocketWebSocket是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在TCP之上,同HTTP一样通过TCP来传输数据,但是它和HTTP最大不同是:WebSocket是一种双向通信协议.由于项目需要创建一个聊天室,需要通过长链接,和后台保持通讯,进行聊天,并且实时进行热点消息的推送.目前Facebook的SocketRocket应该是目前最好的关于SocketRocket使用的框架了.而且简单易用.使用一般一个项目在启动后的某个时机会启动创建一个长链接,如果需要多个就多次创建.如果只要一个就可以封装为一个单例,全局使用.可以使用podpod管理库,在podfile中加入pod'SocketRocket'在使用命令行工具cd到当前工程安装podinstall导入头文件后即可使用.为求稳定,我的做法是copy的FaceBook里SocketRocket库到项目里.-->SocketRocket地址1.首先创建一个名为WebSocketManager的单例类,+(instancetype)shared;2.创建一个枚举,分别表示WebSocket的链接状态typedef
NS_ENUM(NSUInteger,WebSocketConnectType){
WebSocketDefault
=
0,
//初始状态,未连接,不需要重新连接
WebSocketConnect,
//已连接
WebSocketDisconnect
//连接后断开,需要重新连接
};3.创建连接//建立长连接
-
(void)connectServer;4.处理连接成功的结果;-(void)webSocketDidOpen:(RMWebSocket
*)webSocket;
//连接成功回调5.处理连接失败的结果-
(void)webSocket:(SRWebSocket
*)webSocket
didFailWithError:(NSError
*)error;//连接失败回调6.接收消息///接收消息回调,需要提前和后台约定好消息格式.
-
(void)webSocket:(SRWebSocket
*)webSocket
didReceiveMessageWithString:(nonnull
NSString
*)string7.关闭连接-
(void)webSocket:(SRWebSocket
*)webSocket
didCloseWithCode:(NSInteger)code
reason:(NSString
*)reason
wasClean:(BOOL)wasClean;///关闭连接回调的代理8.为保持长链接的连接状态,需要定时向后台发送消息,就是俗称的:心跳包.需要创建一个定时器,固定时间发送消息.9.链接断开情况处理:首先判断是否是主动断开,如果是主动断开就不作处理.如果不是主动断开链接,需要做重新连接的逻辑.具体代码如下:WebSocketManager.h中的代码#import
<foundation
foundation=""
h="">
#import
"RMWebSocket.h"
typedef
NS_ENUM(NSUInteger,WebSocketConnectType){
WebSocketDefault
=
0,
//初始状态,未连接
WebSocketConnect,
//已连接
WebSocketDisconnect
//连接后断开
};
@class
WebSocketManager;
@protocol
WebSocketManagerDelegate
<nsobject>
-
(void)webSocketManagerDidReceiveMessageWithString:(NSString
*)string;
@end
NS_ASSUME_NONNULL_BEGIN
@interface
WebSocketManager
:
NSObject
@property
(nonatomic,
strong)
RMWebSocket
*webSocket;
@property(nonatomic,weak)
id
<websocketmanagerdelegate
nbsp="">
delegate;
@property
(nonatomic,
assign)
BOOL
isConnect;
//是否连接
@property
(nonatomic,
assign)
WebSocketConnectType
connectType;
+(instancetype)shared;
-
(void)connectServer;//建立长连接
-
(void)reConnectServer;//重新连接
-
(void)RMWebSocketClose;//关闭长连接
-
(void)sendDataToServer:(NSString
*)data;//发送数据给服务器
@end
NS_ASSUME_NONNULL_END
</websocketmanagerdelegate>
</nsobject>
</foundation>WebSocketManager.m中的代码#import
"WebSocketManager.h"
@interface
WebSocketManager
()
<rmwebsocketdelegate>
@property
(nonatomic,
strong)
NSTimer
*heartBeatTimer;
//心跳定时器
@property
(nonatomic,
strong)
NSTimer
*netWorkTestingTimer;
//没有网络的时候检测网络定时器
@property
(nonatomic,
assign)
NSTimeInterval
reConnectTime;
//重连时间
@property
(nonatomic,
strong)
NSMutableArray
*sendDataArray;
//存储要发送给服务端的数据
@property
(nonatomic,
assign)
BOOL
isActivelyClose;
//用于判断是否主动关闭长连接,如果是主动断开连接,连接失败的代理中,就不用执行
重新连接方法
@end
@implementation
WebSocketManager
+(instancetype)shared{
static
WebSocketManager
*_instance
=
nil;
static
dispatch_once_t
onceToken;
dispatch_once(&onceToken,
^{
_instance
=
[[self
alloc]init];
});
return
_instance;
}
-
(instancetype)init
{
self
=
[super
init];
if(self){
self.reConnectTime
=
0;
self.isActivelyClose
=
NO;
self.sendDataArray
=
[[NSMutableArray
alloc]
init];
}
return
self;
}
//建立长连接
-
(void)connectServer{
self.isActivelyClose
=
NO;
self.webSocket.delegate
=
nil;
[self.webSocket
close];
_webSocket
=
nil;
//
self.webSocket
=
[[RMWebSocket
alloc]
initWithURL:[NSURL
URLWithString:@"/ws/token=88888888"]];
self.webSocket
=
[[RMWebSocket
alloc]
initWithURL:[NSURL
URLWithString:@"ws://:7272"]];
self.webSocket.delegate
=
self;
[self.webSocket
open];
}
-
(void)sendPing:(id)sender{
[self.webSocket
sendPing:nil
error:NULL];
}
#pragma
mark
#pragma
mark
-
socket
delegate
///开始连接
-(void)webSocketDidOpen:(RMWebSocket
*)webSocket{
NSLog(@"socket
开始连接");
self.isConnect
=
YES;
self.connectType
=
WebSocketConnect;
[self
initHeartBeat];///开始心跳
}
///连接失败
-(void)webSocket:(RMWebSocket
*)webSocket
didFailWithError:(NSError
*)error{
NSLog(@"连接失败");
self.isConnect
=
NO;
self.connectType
=
WebSocketDisconnect;
DLog(@"连接失败,这里可以实现掉线自动重连,要注意以下几点");
DLog(@"1.判断当前网络环境,如果断网了就不要连了,等待网络到来,在发起重连");
DLog(@"3.连接次数限制,如果连接失败了,重试10次左右就可以了");
//判断网络环境
if
(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
==
AFNetworkReachabilityStatusNotReachable){
//没有网络
[self
noNetWorkStartTestingTimer];//开启网络检测定时器
}else{
//有网络
[self
reConnectServer];//连接失败就重连
}
}
///接收消息
-(void)webSocket:(RMWebSocket
*)webSocket
didReceiveMessageWithString:(NSString
*)string{
NSLog(@"接收消息
%@",string);
if
([self.delegate
respondsToSelector:@selector(webSocketManagerDidReceiveMessageWithString:)])
{
[self.delegate
webSocketManagerDidReceiveMessageWithString:string];
}
}
///关闭连接
-(void)webSocket:(RMWebSocket
*)webSocket
didCloseWithCode:(NSInteger)code
reason:(NSString
*)reason
wasClean:(BOOL)wasClean{
self.isConnect
=
NO;
if(self.isActivelyClose){
self.connectType
=
WebSocketDefault;
return;
}else{
self.connectType
=
WebSocketDisconnect;
}
DLog(@"被关闭连接,code:%ld,reason:%@,wasClean:%d",code,reason,wasClean);
[self
destoryHeartBeat];
//断开连接时销毁心跳
//判断网络环境
if
(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
==
AFNetworkReachabilityStatusNotReachable){
//没有网络
[self
noNetWorkStartTestingTimer];//开启网络检测
}else{
//有网络
NSLog(@"关闭连接");
_webSocket
=
nil;
[self
reConnectServer];//连接失败就重连
}
}
///ping
-(void)webSocket:(RMWebSocket
*)webSocket
didReceivePong:(NSData
*)pongData{
NSLog(@"接受pong数据-->
%@",pongData);
}
#pragma
mark
-
NSTimer
//初始化心跳
-
(void)initHeartBeat{
//心跳没有被关闭
if(self.heartBeatTimer)
{
return;
}
[self
destoryHeartBeat];
dispatch_main_async_safe(^{
self.heartBeatTimer
=
[NSTimer
timerWithTimeInterval:10
target:self
selector:@selector(senderheartBeat)
userInfo:nil
repeats:true];
[[NSRunLoop
currentRunLoop]addTimer:self.heartBeatTimer
forMode:NSRunLoopCommonModes];
})
}
//重新连接
-
(void)reConnectServer{
if(self.webSocket.readyState
==
RM_OPEN){
return;
}
if(self.reConnectTime
>
1024){
//重连10次
2^10
=
1024
self.reConnectTime
=
0;
return;
}
WS(weakSelf);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(self.reConnectTime
*NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
if(weakSelf.webSocket.readyState
==
RM_OPEN
&&
weakSelf.webSocket.readyState
==
RM_CONNECTING)
{
return;
}
[weakSelf
connectServer];
//
CTHLog(@"正在重连");
if(weakSelf.reConnectTime
==
0){
//重连时间2的指数级增长
weakSelf.reConnectTime
=
2;
}else{
weakSelf.reConnectTime
*=
2;
}
});
}
//发送心跳
-
(void)senderheartBeat{
//和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小
WS(weakSelf);
dispatch_main_async_safe(^{
if(weakSelf.webSocket.readyState
==
RM_OPEN){
[weakSelf
sendPing:nil];
}
});
}
//没有网络的时候开始定时
--
用于网络检测
-
(void)noNetWorkStartTestingTimer{
WS(weakSelf);
dispatch_main_async_safe(^{
weakSWorkTestingTimer
=
[NSTimer
scheduledTimerWithTimeInterval:1.0
target:weakSelf
selector:@selector(noNetWorkStartTesting)
userInfo:nil
repeats:YES];
[[NSRunLoop
currentRunLoop]
addTimer:weakSWorkTestingTimer
forMode:NSDefaultRunLoopMode];
});
}
//定时检测网络
-
(void)noNetWorkStartTesting{
//有网络
if(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
!=
AFNetworkReachabilityStatusNotReachable)
{
//关闭网络检测定时器
[self
destoryNetWorkStartTesting];
//开始重连
[self
reConnectServer];
}
}
//取消网络检测
-
(void)destoryNetWorkStartTesting{
WS(weakSelf);
dispatch_main_async_safe(^{
if(weakSWorkTestingTimer)
{
[weakSWorkTestingTimer
invalidate];
weakSWorkTestingTimer
=
nil;
}
});
}
//取消心跳
-
(void)destoryHeartBeat{
WS(weakSelf);
dispatch_main_async_safe(^{
if(weakSelf.heartBeatTimer)
{
[weakSelf.heartBeatTimer
invalidate];
weakSelf.heartBeatTimer
=
nil;
}
});
}
//关闭长连接
-
(void)RMWebSocketClose{
self.isActivelyClose
=
YES;
self.isConnect
=
NO;
self.connectType
=
WebSocketDefault;
if(self.webSocket)
{
[self.webSocket
close];
_webSocket
=
nil;
}
//关闭心跳定时器
[self
destoryHeartBeat];
//关闭网络检测定时器
[self
destoryNetWorkStartTesting];
}
//发送数据给服务器
-
(void)sendDataToServer:(NSString
*)data{
[self.sendDataArray
addObject:data];
//[_webSocket
sendString:data
error:NULL];
//没有网络
if
(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
==
AFNetworkReachabilityStatusNotReachable)
{
//开启网络检测定时器
[self
noNetWorkStartTestingTimer];
}
else
//有网络
{
if(self.webSocket
!=
nil)
{
//
只有长连接OPEN开启状态才能调
send
方法,不然会Crash
if(self.webSocket.readyState
==
RM_OPEN)
{
//
if
(self.sendDataArray.count
>
0)
//
{
//
NSString
*data
=
self.sendDataArray[0];
[_webSocket
sendString:data
error:NULL];
//发送数据
//
[self.sendDataArray
removeObjectAtInd
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 网络图试题及答案
- 天津自主招生试题及答案
- 2025年资金规划与分配谅解协议
- 2025年劳动合同保密协议样本
- 2025年全渠道媒体广告合作协议
- 2025年桩机工程劳务合作协议
- 2025年农村经济振兴策划投资协议
- 2025年标准离婚协议样本规范
- 2025年医疗责任赔偿协议书策划要点与范本
- 2025年能源供需合作框架协议
- 气压传动课件 项目八任务一 公共汽车门气压传动系统
- 制鞋业鞋类产品设计与生产流程规范
- DB42-T 2275-2024 消防给水设施物联网系统技术标准
- Unit4Friendsforever短文巧记单词学习任务单高中英语
- 2024年春七年级地理下册 第8章 第三节 俄罗斯教案 (新版)湘教版
- 1旅游概述《旅游学概论》省公开课一等奖全国示范课微课金奖课件
- DL∕T 5390-2014 发电厂和变电站照明设计技术规定
- 2024-2030年电影放映机行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 日内高频交易策略研究
- 2024年长沙市中考数学真题试卷及答案
- 语文综合实践《走进传统节日探寻文化根脉》课件-【中职专用】高一语文同步课件(高教版2023·基础模块下册)
评论
0/150
提交评论