版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】怎么在iOS中實現(xiàn)WebSocket長鏈接
今天就跟大家聊聊有關(guān)怎么在iOS中實現(xiàn)WebSocket長鏈接,可能很多人都不太了解,為了讓大家更加了解,在下給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。WebSocketWebSocket是HTML5一種新的協(xié)議。它實現(xiàn)了瀏覽器與服務(wù)器全雙工通信,能更好的節(jié)省服務(wù)器資源和帶寬并達到實時通訊,它建立在TCP之上,同HTTP一樣通過TCP來傳輸數(shù)據(jù),但是它和HTTP最大不同是:WebSocket是一種雙向通信協(xié)議.由于項目需要創(chuàng)建一個聊天室,需要通過長鏈接,和后臺保持通訊,進行聊天,并且實時進行熱點消息的推送.目前Facebook的SocketRocket應(yīng)該是目前最好的關(guān)于SocketRocket使用的框架了.而且簡單易用.使用一般一個項目在啟動后的某個時機會啟動創(chuàng)建一個長鏈接,如果需要多個就多次創(chuàng)建.如果只要一個就可以封裝為一個單例,全局使用.可以使用podpod管理庫,在podfile中加入pod'SocketRocket'在使用命令行工具cd到當前工程安裝podinstall導入頭文件后即可使用.為求穩(wěn)定,我的做法是copy的FaceBook里SocketRocket庫到項目里.-->SocketRocket地址1.首先創(chuàng)建一個名為WebSocketManager的單例類,+(instancetype)shared;2.創(chuàng)建一個枚舉,分別表示W(wǎng)ebSocket的鏈接狀態(tài)typedef
NS_ENUM(NSUInteger,WebSocketConnectType){
WebSocketDefault
=
0,
//初始狀態(tài),未連接,不需要重新連接
WebSocketConnect,
//已連接
WebSocketDisconnect
//連接后斷開,需要重新連接
};3.創(chuàng)建連接//建立長連接
-
(void)connectServer;4.處理連接成功的結(jié)果;-(void)webSocketDidOpen:(RMWebSocket
*)webSocket;
//連接成功回調(diào)5.處理連接失敗的結(jié)果-
(void)webSocket:(SRWebSocket
*)webSocket
didFailWithError:(NSError
*)error;//連接失敗回調(diào)6.接收消息///接收消息回調(diào),需要提前和后臺約定好消息格式.
-
(void)webSocket:(SRWebSocket
*)webSocket
didReceiveMessageWithString:(nonnull
NSString
*)string7.關(guān)閉連接-
(void)webSocket:(SRWebSocket
*)webSocket
didCloseWithCode:(NSInteger)code
reason:(NSString
*)reason
wasClean:(BOOL)wasClean;///關(guān)閉連接回調(diào)的代理8.為保持長鏈接的連接狀態(tài),需要定時向后臺發(fā)送消息,就是俗稱的:心跳包.需要創(chuàng)建一個定時器,固定時間發(fā)送消息.9.鏈接斷開情況處理:首先判斷是否是主動斷開,如果是主動斷開就不作處理.如果不是主動斷開鏈接,需要做重新連接的邏輯.具體代碼如下:WebSocketManager.h中的代碼#import
<foundation
foundation=""
h="">
#import
"RMWebSocket.h"
typedef
NS_ENUM(NSUInteger,WebSocketConnectType){
WebSocketDefault
=
0,
//初始狀態(tài),未連接
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;//關(guān)閉長連接
-
(void)sendDataToServer:(NSString
*)data;//發(fā)送數(shù)據(jù)給服務(wù)器
@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;
//沒有網(wǎng)絡(luò)的時候檢測網(wǎng)絡(luò)定時器
@property
(nonatomic,
assign)
NSTimeInterval
reConnectTime;
//重連時間
@property
(nonatomic,
strong)
NSMutableArray
*sendDataArray;
//存儲要發(fā)送給服務(wù)端的數(shù)據(jù)
@property
(nonatomic,
assign)
BOOL
isActivelyClose;
//用于判斷是否主動關(guān)閉長連接,如果是主動斷開連接,連接失敗的代理中,就不用執(zhí)行
重新連接方法
@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(@"連接失敗,這里可以實現(xiàn)掉線自動重連,要注意以下幾點");
DLog(@"1.判斷當前網(wǎng)絡(luò)環(huán)境,如果斷網(wǎng)了就不要連了,等待網(wǎng)絡(luò)到來,在發(fā)起重連");
DLog(@"3.連接次數(shù)限制,如果連接失敗了,重試10次左右就可以了");
//判斷網(wǎng)絡(luò)環(huán)境
if
(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
==
AFNetworkReachabilityStatusNotReachable){
//沒有網(wǎng)絡(luò)
[self
noNetWorkStartTestingTimer];//開啟網(wǎng)絡(luò)檢測定時器
}else{
//有網(wǎng)絡(luò)
[self
reConnectServer];//連接失敗就重連
}
}
///接收消息
-(void)webSocket:(RMWebSocket
*)webSocket
didReceiveMessageWithString:(NSString
*)string{
NSLog(@"接收消息
%@",string);
if
([self.delegate
respondsToSelector:@selector(webSocketManagerDidReceiveMessageWithString:)])
{
[self.delegate
webSocketManagerDidReceiveMessageWithString:string];
}
}
///關(guān)閉連接
-(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(@"被關(guān)閉連接,code:%ld,reason:%@,wasClean:%d",code,reason,wasClean);
[self
destoryHeartBeat];
//斷開連接時銷毀心跳
//判斷網(wǎng)絡(luò)環(huán)境
if
(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
==
AFNetworkReachabilityStatusNotReachable){
//沒有網(wǎng)絡(luò)
[self
noNetWorkStartTestingTimer];//開啟網(wǎng)絡(luò)檢測
}else{
//有網(wǎng)絡(luò)
NSLog(@"關(guān)閉連接");
_webSocket
=
nil;
[self
reConnectServer];//連接失敗就重連
}
}
///ping
-(void)webSocket:(RMWebSocket
*)webSocket
didReceivePong:(NSData
*)pongData{
NSLog(@"接受pong數(shù)據(jù)-->
%@",pongData);
}
#pragma
mark
-
NSTimer
//初始化心跳
-
(void)initHeartBeat{
//心跳沒有被關(guān)閉
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的指數(shù)級增長
weakSelf.reConnectTime
=
2;
}else{
weakSelf.reConnectTime
*=
2;
}
});
}
//發(fā)送心跳
-
(void)senderheartBeat{
//和服務(wù)端約定好發(fā)送什么作為心跳標識,盡可能的減小心跳包大小
WS(weakSelf);
dispatch_main_async_safe(^{
if(weakSelf.webSocket.readyState
==
RM_OPEN){
[weakSelf
sendPing:nil];
}
});
}
//沒有網(wǎng)絡(luò)的時候開始定時
--
用于網(wǎng)絡(luò)檢測
-
(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];
});
}
//定時檢測網(wǎng)絡(luò)
-
(void)noNetWorkStartTesting{
//有網(wǎng)絡(luò)
if(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
!=
AFNetworkReachabilityStatusNotReachable)
{
//關(guān)閉網(wǎng)絡(luò)檢測定時器
[self
destoryNetWorkStartTesting];
//開始重連
[self
reConnectServer];
}
}
//取消網(wǎng)絡(luò)檢測
-
(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;
}
});
}
//關(guān)閉長連接
-
(void)RMWebSocketClose{
self.isActivelyClose
=
YES;
self.isConnect
=
NO;
self.connectType
=
WebSocketDefault;
if(self.webSocket)
{
[self.webSocket
close];
_webSocket
=
nil;
}
//關(guān)閉心跳定時器
[self
destoryHeartBeat];
//關(guān)閉網(wǎng)絡(luò)檢測定時器
[self
destoryNetWorkStartTesting];
}
//發(fā)送數(shù)據(jù)給服務(wù)器
-
(void)sendDataToServer:(NSString
*)data{
[self.sendDataArray
addObject:data];
//[_webSocket
sendString:data
error:NULL];
//沒有網(wǎng)絡(luò)
if
(AFNetworkReachabilityManager.sharedMworkReachabilityStatus
==
AFNetworkReachabilityStatusNotReachable)
{
//開啟網(wǎng)絡(luò)檢測定時器
[self
noNetWorkStartTestingTimer];
}
else
//有網(wǎng)絡(luò)
{
if(self.webSocket
!=
nil)
{
//
只有長連接OPEN開啟狀態(tài)才能調(diào)
send
方法,不然會Crash
if(self.webSocket.readyState
==
RM_OPEN)
{
//
if
(self.sendDataArray.count
>
0)
//
{
//
NSString
*data
=
self.sendDataArray[0];
[_webSocket
sendString:data
error:NULL];
//發(fā)送數(shù)據(jù)
//
[self.sendDataArray
removeObjectAtInd
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工作述職報告3篇
- 二零二五年度綠色環(huán)保廣告字制作與安裝服務(wù)合同3篇
- 2025年度跨行業(yè)員工借調(diào)與資源共享合作協(xié)議3篇
- 2025年度年度勞動爭議調(diào)解律師委托協(xié)議終止書3篇
- 2025年度無人機農(nóng)業(yè)病蟲害防治與智慧農(nóng)業(yè)平臺合同3篇
- 2025年度農(nóng)莊租賃與農(nóng)業(yè)資源整合合同3篇
- 二零二五年度獸醫(yī)疾病防控中心獸醫(yī)聘用協(xié)議3篇
- 二零二五年度月嫂服務(wù)滿意度評價及改進合同2篇
- 二零二五年度化學論文版權(quán)轉(zhuǎn)讓及國際學術(shù)交流合同3篇
- 2025年度教育資源共享合作協(xié)議書模板集3篇
- 2023教學工作檢查評估總結(jié)
- 銅排設(shè)計技術(shù)規(guī)范
- 英國文學史及選讀復習要點總結(jié)
- 貴州省貴陽市花溪區(qū)2023-2024學年數(shù)學三年級第一學期期末聯(lián)考試題含答案
- 整改回復書樣板后邊附帶圖片
- 中小學校園人車分流方案模板
- 廣東省惠州市博羅縣2022-2023學年六年級上學期期末數(shù)學試卷
- 2023年04月2023年外交學院招考聘用筆試參考題庫附答案解析
- 中國自身免疫性腦炎診治專家共識2023年版
- 單片機與微機原理及應(yīng)用第二版張迎新習題答案
- 深部真菌病課件
評論
0/150
提交評論