iOSアクセスwebsocket


1,websocket
Websocketはhtml 5が提案したプロトコル仕様である.ブラウザとサーバの全二重通信を実現し、サーバ資源と帯域幅をよりよく節約することができ、websocketは通信の規範を約束し、握手のメカニズムを通じて、クライアント(ブラウザ)とサーバ(webserver)の間にtcpのような接続を確立することができ、c-s間の通信を便利にする.Websocketが登場する前に、webインタラクションは一般的にhttpプロトコルに基づく短い接続または長い接続である.WebSocketは、クライアントとサービス側とのリアルタイム通信を解決するための技術である.Websocketプロトコルは本質的にtcpベースのプロトコルであり、HTTP/HTTPSプロトコルを介して特殊なhttpリクエストを開始して握手した後、データを交換するためのTCP接続を作成し、その後、サービス側とクライアントはこのTCP接続を通じてリアルタイム通信を行い、httpと最大の違いは、websocketは双方向通信プロトコルであり、接続が確立された後、Websocketサーバとクライアントは、socketのようにnegativeが積極的に相手にデータを送信または受信します.
2,websocketの利点
以前はウェブサーバがプッシュ技術やインスタント通信を実現していたが、ポーリング(polling)を用いており、特徴的な時間間隔(例えば1秒)でブラウザから自動的に要求を出し、サーバのメッセージをアクティブに引き戻す必要があった.この場合、サービスに絶えず要求を送信する必要があったが、HTTP requestのヘッダは非常に長い.含まれているデータは小さな値にすぎない可能性があります.これにより、帯域幅とサーバリソースが大幅に消費されます.
WebSocket APIの最も偉大な点は、サーバとクライアントが所定の時間範囲内の任意の時点で、互いに情報をプッシュできることである.ブラウザとサーバは握手の動作をするだけで、接続が確立された後、サーバは自発的にクライアントにデータを転送することができ、クライアントはいつでもサーバにデータを送信することができます.また,サーバとクライアントとの間で交換されるヘッダ情報は小さい.
3,websocketの使い方
『1』podインポートを使用しています
pod 'SocketRocket'
《2》
ライブラリをプロジェクトにインポートした後、まず1つをカプセル化します.
HHWebSocketManager
単一の例
//.h
#import 
#import 

extern NSString * const kNeedPayOrderNote;
extern NSString * const kWebSocketDidOpenNote;
extern NSString * const kWebSocketDidCloseNote;
extern NSString * const kWebSocketdidReceiveMessageNote;

@interface HHWebSocketManager : NSObject
    //       
@property (nonatomic,assign,readonly) SRReadyState socketReadyState;

+ (HHWebSocketManager *)instance;

- (void)SRWebSocketOpen;//    
- (void)SRWebSocketClose;//    
- (void)sendData:(id)data;//    


@end
//.m
#import "HHWebSocketManager.h"

NSString * const kNeedPayOrderNote = @"kNeedPayOrderNote";
NSString * const kWebSocketDidOpenNote = @"kWebSocketdidReceiveMessageNote";
NSString * const kWebSocketDidCloseNote = @"kWebSocketDidCloseNote";
NSString * const kWebSocketdidReceiveMessageNote = @"kWebSocketdidReceiveMessageNote";

@interface HHWebSocketManager()
{
    int _index;
    NSTimer * heartBeat;
    NSTimeInterval reConnectTime;
    
}
@property (nonatomic,strong) SRWebSocket *socket;

@end

@implementation HHWebSocketManager

+(HHWebSocketManager *)instance{
    static HHWebSocketManager *Instance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        Instance = [[HHWebSocketManager alloc] init];
    });
    return Instance;
}

#pragma mark - **************** public methods
-(void)SRWebSocketOpen{
    
        //      url return
    if (self.socket) {
        return;
    }
    self.socket = [[SRWebSocket alloc] initWithURLRequest:
                   [NSURLRequest requestWithURL:[NSURL URLWithString:@"youurl"]]];//           
    NSLog(@"   websocket  :%@",self.socket.url.absoluteString);
    self.socket.delegate = self;
    //    
    [self.socket open];
}

-(void)SRWebSocketClose{
    if (self.socket){
        [self.socket close];
        self.socket = nil;
        //         
        [self destoryHeartBeat];
    }
}

#define WeakSelf(ws) __weak __typeof(&*self)weakSelf = self
- (void)sendData:(id)data {
    NSLog(@"socketSendData --------------- %@",data);
    
    WeakSelf(ws);
    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) {
                NSLog(@"     ,               ");
                    //   2      socket.readyState   ,   10    
                    //          SR_OPEN      [ws.socket send:data]     
                    //    10         ,           ,            ,    
                    //      ,           
                [self reConnect];
                
            } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
                    // websocket    ,   reConnect     
                NSLog(@"  ");
                [self reConnect];
            }
        } else {
            NSLog(@"   ,    ,     socket       nil  ");
            NSLog(@"                   ,       ,socket==nil     ");
        }
    });
}

#pragma mark - **************** private mothodes
    //    
- (void)reConnect
{
    [self SRWebSocketClose];
        //                 5  2^5 = 64
    if (reConnectTime > 64) {
            //          ,        
        return;
    }
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.socket = nil;
        [self SRWebSocketOpen];
        NSLog(@"  ");
    });
    
        //    2      
    if (reConnectTime == 0) {
        reConnectTime = 2;
    }else{
        reConnectTime *= 2;
    }
}

    //    
- (void)destoryHeartBeat
{
    dispatch_main_async_safe(^{
        if (heartBeat) {
            if ([heartBeat respondsToSelector:@selector(isValid)]){
                if ([heartBeat isValid]){
                    [heartBeat invalidate];
                    heartBeat = nil;
                }
            }
        }
    })
}

    //     
- (void)initHeartBeat
{
    dispatch_main_async_safe(^{
        [self destoryHeartBeat];
            //     3  ,NAT     5  
        heartBeat = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(sentheart) userInfo:nil repeats:YES];
            //                 ,           
        [[NSRunLoop currentRunLoop] addTimer:heartBeat forMode:NSRunLoopCommonModes];
    })
}

-(void)sentheart{
        //                          ping                data  
    [self sendData:@"heart"];
}

    //pingPong
- (void)ping{
    if (self.socket.readyState == SR_OPEN) {
        [self.socket sendPing:nil];
    }
}

#pragma mark - socket delegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
        //               
    reConnectTime = 0;
        //    
    [self initHeartBeat];
    if (webSocket == self.socket) {
        NSLog(@"************************** socket     ************************** ");
        [[NSNotificationCenter defaultCenter] postNotificationName:kWebSocketDidOpenNote object:nil];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket     ************************** ");
        _socket = nil;
            //       
        [self reConnect];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket    ************************** ");
        NSLog(@"     ,code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
        [self SRWebSocketClose];
        [[NSNotificationCenter defaultCenter] postNotificationName:kWebSocketDidCloseNote object:nil];
    }
}

/*            pong  ,         pong   ,
            ,                   ,
                ,       ,           ping  ,
              ,                 ping  ,         
 */
-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
    NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
    NSLog(@"reply===%@",reply);
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
    
    if (webSocket == self.socket) {
        NSLog(@"************************** socket     ************************** ");
        NSLog(@"        message   json         ,       ,          ");
        NSLog(@"message:%@",message);
        
        [[NSNotificationCenter defaultCenter] postNotificationName:kWebSocketdidReceiveMessageNote object:message];
    }
}

#pragma mark - **************** setter getter
- (SRReadyState)socketReadyState{
    return self.socket.readyState;
}

-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
『3』の使い方
//     socket     
[[SocketRocketUtility instance] SRWebSocketOpen];
//            
[[SocketRocketUtility instance] SRWebSocketClose];

《4》このフレームワークの最後の1つを使うのはとても重要で、注意しなければなりません
このフレームワークでカプセル化されたwebscoketは、sendPing senddataメソッドを呼び出す前に、現在のscoketが接続されているかどうかを判断しなければなりません.接続状態でなければ、プログラムはcrashになります.
《5》通知の追加
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(SRWebSocketDidOpen) name:@"kWebSocketDidOpenNote" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(SRWebSocketDidReceiveMsg:) name:@"kWebSocketdidReceiveMessageNote" object:nil];
- (void)SRWebSocketDidOpen {
    NSLog(@"    ");
    //          。。。
        
}

- (void)SRWebSocketDidReceiveMsg:(NSNotification *)note {
    //            
    NSString * message = note.object;
    NSLog(@"%@",message);
}