WebSocket:SocketRocketパッケージ
7613 ワード
WebSocket WebSocketは、HTML 5が提供し始めた単一のTCP接続上でフルデュプレクス通信を行うプロトコルである. HTTPプロトコルは、無状態、無接続、一方向のアプリケーション層プロトコルである.リクエスト/レスポンスモデルを採用しています.通信要求はクライアントからのみ開始され,サービス側は要求に対して応答処理を行う.この通信モデルには、HTTPプロトコルでは、サーバがクライアントに積極的にメッセージを送信することができないという弊害がある.このような一方向要求の特徴は,サーバが連続的に状態が変化すると,クライアントが知るのは非常に面倒であることに決まっている.ほとんどのWebアプリケーションでは、頻繁な非同期JavaScriptとXML(AJAX)リクエストによって長いポーリングが実現されます.ポーリングの効率が低く、リソースが非常に浪費されます(接続を停止しないか、HTTP接続を常に開く必要があるため). WebSocket接続により、クライアントとサーバとの間でフルデュプレクス通信が可能になり、どちらも確立された接続によってデータを他端にプッシュできます.WebSocketは1回の接続を確立するだけで、接続状態を維持することができます.これは、ポーリング方式による接続の継続的な確立に比べて、明らかに効率が大幅に向上します.
WebSocketとSocketの関係
Socketは実際にはプロトコルではなく、TCPやUDPの使用を容易にするために抽象化された層であり、アプリケーション層と伝送制御層の間に位置するインタフェースのセットである.アプリケーション層とTCP/IPプロトコルファミリー通信の中間ソフトウェア抽象層であり、インタフェースのセットである.設計モードでは、Socketは複雑なTCP/IPプロトコルファミリーをSocketインタフェースの後ろに隠し、ユーザーにとって簡単なインタフェースのセットがすべてであり、Socketにデータを組織させ、指定されたプロトコルに合致させる.2台のホストが通信する場合はSocketで接続する必要があり、SocketはTCP/IPプロトコルを利用してTCP接続を確立する.TCP接続は下位層のIPプロトコルに依存し,IPプロトコルの接続はリンク層などより下位層に依存する.WebSocketは典型的なアプリケーション層プロトコルです.違いはSocketがトランスポート制御層プロトコル,WebSocketがアプリケーション層プロトコルである.
WebSocketのフレームワークSocketRocket
SocketRocketツールクラスパッケージ
カプセル化されたステップロジック 1.オープン接続 2.開心拍数 心拍数のように一定時間おきに送信し、このクライアントがまだ生きていることをサーバに伝えます.実はこれは長い接続を保つためで、このパッケージの内容については、特に規定はありませんが、一般的には小さなパッケージ、あるいはパッケージの頭だけを含む空のパッケージです.だからドキドキはタイマー 3.再接続機構 自分のネットワークが切断されたとき、再接続する必要があります.バックグラウンドがアクティブに切断され、正常に切断されると、
WebSocketとSocketの関係
Socketは実際にはプロトコルではなく、TCPやUDPの使用を容易にするために抽象化された層であり、アプリケーション層と伝送制御層の間に位置するインタフェースのセットである.アプリケーション層とTCP/IPプロトコルファミリー通信の中間ソフトウェア抽象層であり、インタフェースのセットである.設計モードでは、Socketは複雑なTCP/IPプロトコルファミリーをSocketインタフェースの後ろに隠し、ユーザーにとって簡単なインタフェースのセットがすべてであり、Socketにデータを組織させ、指定されたプロトコルに合致させる.2台のホストが通信する場合はSocketで接続する必要があり、SocketはTCP/IPプロトコルを利用してTCP接続を確立する.TCP接続は下位層のIPプロトコルに依存し,IPプロトコルの接続はリンク層などより下位層に依存する.WebSocketは典型的なアプリケーション層プロトコルです.違いはSocketがトランスポート制御層プロトコル,WebSocketがアプリケーション層プロトコルである.
WebSocketのフレームワークSocketRocket
SocketRocket
#import
#import
extern NSString * const GQNotification_SocketRocketDidOpen;
extern NSString * const GQNotification_SocketRocketDidClose;
extern NSString * const GQNotification_SocketRocketDidReceive;
@interface GQSocketRocketManager : NSObject
+ (instancetype)gq_shareInstance;
/** */
@property (nonatomic, assign, readonly) SRReadyState socketReadyState;
/** */
- (void)gq_openWithURLString:(NSString *)urlString;
/** */
- (void)gq_close;
/** */
- (void)gq_sendData:(id)data;
@end
#import "GQSocketRocketManager.h"
#import "GQKit.h"
NSString * const GQNotification_SocketRocketDidOpen = @"GQNotification_SocketRocketDidOpen";
NSString * const GQNotification_SocketRocketDidClose = @"GQNotification_SocketRocketDidClose";
NSString * const GQNotification_SocketRocketDidReceive = @"GQNotification_SocketRocketDidReceive";
@interface GQSocketRocketManager()
@property (nonatomic,strong) SRWebSocket *socket;
@property (nonatomic,strong) NSTimer *heartBeat;
@property (nonatomic,assign) NSTimeInterval reConnectTime;
@property (nonatomic,copy) NSString *urlString;
@end
@implementation GQSocketRocketManager
+ (instancetype)gq_shareInstance {
static GQSocketRocketManager *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[GQSocketRocketManager alloc] init];
});
return instance;
}
- (void)gq_openWithURLString:(NSString *)urlString {
if (self.socket) {
return;
}
if (!urlString) {
return;
}
self.urlString = urlString;
self.socket = [[SRWebSocket alloc] initWithURLRequest:
[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
self.socket.delegate = self;
[self.socket open];
}
- (void)gq_close {
if (self.socket){
[self.socket close];
self.socket = nil;
[self destoryHeartBeat];
}
}
- (void)gq_sendData:(id)data {
__weak __typeof(self) weakSelf = self;
dispatch_queue_t queue = dispatch_queue_create("zy", NULL);
dispatch_async(queue, ^{
if (weakSelf.socket != nil) {
// SR_OPEN send ,
if (weakSelf.socket.readyState == SR_OPEN) {
[weakSelf.socket send:data]; //
} else if (weakSelf.socket.readyState == SR_CONNECTING) {
GQLog(@" ");
[self reConnect];
} else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
[self reConnect];
}
} else {
}
});
}
//
- (void)reConnect {
[self gq_close];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.socket = nil;
[self gq_openWithURLString:self.urlString];
});
if (self.reConnectTime == 0) {
self.reConnectTime = 2;
}
}
//
- (void)destoryHeartBeat {
GQ_dispatch_main_async_safe(^{
if (self.heartBeat) {
if ([self.heartBeat respondsToSelector:@selector(isValid)]){
if ([self.heartBeat isValid]){
[self.heartBeat invalidate];
self.heartBeat = nil;
}
}
}
})
}
//
- (void)initHeartBeat {
GQ_dispatch_main_async_safe(^{
[self destoryHeartBeat];
self.heartBeat = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.heartBeat forMode:NSRunLoopCommonModes];
})
}
-(void)sentheart {
//
[self gq_sendData:[@"1" dataUsingEncoding:NSUTF8StringEncoding]];
}
#pragma mark - delegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
//
self.reConnectTime = 0;
//
[self initHeartBeat];
if (webSocket == self.socket) {
GQLog(@"socket ");
[[NSNotificationCenter defaultCenter] postNotificationName:GQNotification_SocketRocketDidOpen object:nil];
}
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
if (webSocket == self.socket) {
GQLog(@"socket ");
_socket = nil;
[self reConnect];
}
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
if (webSocket == self.socket) {
GQLog(@"socket ,code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
[self reConnect];
}
}
/* pong , pong ,
, ,
, , ping ,
*/
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
// NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
if (webSocket == self.socket) {
GQLog(@"socket message:%@",message);
[[NSNotificationCenter defaultCenter] postNotificationName:GQNotification_SocketRocketDidReceive object:message];
}
}
- (SRReadyState)socketReadyState {
return self.socket.readyState;
}
@end
カプセル化されたステップロジック
- (void)gq_openWithURLString:(NSString *)urlString;
heartBeat
で、3秒ごとに送信されます.心拍数の送信は実際にはpingメッセージであり、そのサーバはpongメッセージを返し、-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload
であり、pongを受信できないのは心拍数が切れたことである.- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
が呼び出され、処理は接続SRWebSocketClose
を閉じるか、再接続するか、一般的に後者である.バックグラウンドがネットワークが悪い場合、またはクラッシュした場合、- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error
が呼び出され、再接続されます.