【移動應(yīng)用開發(fā)技術(shù)】怎么在iOS中實現(xiàn)WebSocket長鏈接_第1頁
【移動應(yīng)用開發(fā)技術(shù)】怎么在iOS中實現(xiàn)WebSocket長鏈接_第2頁
【移動應(yīng)用開發(fā)技術(shù)】怎么在iOS中實現(xiàn)WebSocket長鏈接_第3頁
【移動應(yīng)用開發(fā)技術(shù)】怎么在iOS中實現(xiàn)WebSocket長鏈接_第4頁
【移動應(yīng)用開發(fā)技術(shù)】怎么在iOS中實現(xiàn)WebSocket長鏈接_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論