This is the seventh day of my participation in the August Challenge. Check out the details: The August Challenge used socke. IO because the project aurora push was sometimes delayed, and the iOS side also needed to integrate the responding Socket.

1. The concept

Socket: The so-called Socket is an abstraction of the endpoints for two-way communication between application processes on different hosts in the network. A socket is the communication end of a network process. It provides a mechanism for application layer processes to exchange data using network protocols. From the position, the socket is connected to the application process, the network protocol stack, is the application program through the network protocol communication interface, is the application program and network protocol root interface for interaction. WebSocket: WebSocket makes it easier to exchange data between a client and a server and allows the server to proactively push data to the client. In the WebSocket API, a handshake between the browser and the server is all that is needed to create a persistent connection and two-way data transfer. Many websites use polling to implement push technology. Polling is when the browser makes an HTTP request to the server at a specific time interval (such as every second), and the server returns the latest data to the client browser. This traditional model has obvious disadvantages, that is, the browser needs to constantly send requests to the server, but THE HTTP request may contain long headers, in which the actual valid data may be only a small part, obviously this will waste a lot of bandwidth and other resources. A relatively new technique for polling is Comet. This technique allows two-way communication, but still requires repeated requests. And long links, which are common in Comet, also consume server resources. In this case, HTML5 defines the WebSocket protocol, can better save server resources and bandwidth, and can be more real-time communication. On iOS, we know that the socket open source framework is CocoaAsyncSocket, and webSocket frameworks are Facebook SocketRocket and Socket.io-client-Swift. Next look at socket.io-client-swif in OC.

2. The Socket. IO – the Client – Swif use

2.1 the import

use_frameworks!

target 'YourApp' do
    pod 'Socket.IO-Client-Swift'.'~ > 15.2.0'
end

Copy the code

To use SWIFT in OC, add a bridge

There is no SWIFT file in the OC project. Create a SWIFT file at will

Import:

Swift:

import SocketIO
Copy the code

Objective-C:

@import SocketIO;
Copy the code

2.2 applications

- (SocketManager *)manger {

    if(! _manger) { NSString *url = WebSocket_url;// The URL of the backend convention. ConnectParams is the custom parameter of the backend convention

        NSDictionary *paramDict = @{@"log": @YES,

                                    @"compress": @NO ,

                                    @"connectParams": @ {@"userID":[NSString stringWithFormat:@"kbdc_0_%@",[UserConfig shareInstance].model.id]}

                                    };

        _manger = [[SocketManager alloc] initWithSocketURL:[NSURL URLWithString:url] config:paramDict];

        

    }
    return _manger;

}
- (SocketIOClient *)socket {

    if(! _socket) {// _socket = [self.manger socketForNamespace:@"saas"]; // Pass in the convention namespace

         _socket = self.manger.defaultSocket; // If namespaces are not distinguished, go to the default socket

        

    }

    return _socket;

}
Copy the code
  • connectTo connect
// Establish a long connection

- (void)connectServer{

    self.isActivelyClose = NO;

    [self.socket disconnect];// If so, disconnect the connection

    _manger = nil;

    _socket = nil;

    [self.socket connect];// Lazy load reconnect

    [self blockDealWithMethod];// Listen for callbacks

}
Copy the code

The main thing is to initialize the Manager, and then the socket will connect.

  • callbackListen to the callback
- (void)blockDealWithMethod

{

    @weakify(self)

    

    [self.socket on:@"connect" callback:^(NSArray * _Nonnull dataArray, SocketAckEmitter * _Nonnull emitter) {

        [self webSocketDidOpen];

           NSLog(@"Link successful connect:%@",dataArray);


       }];

    [self.socket on:@"reconnect_failed" callback:^(NSArray * _Nonnull dataArray, SocketAckEmitter * _Nonnull emitter) {

        @strongify(self)

        [self webSocketDidFailWithError:nil];

            NSLog(@"Failed to reconnect %@",dataArray);

    

        }];

    

     [self.socket on:@"sendMsg" callback:^(NSArray * _Nonnull dataArray, SocketAckEmitter * _Nonnull emitter) {

         @strongify(self)

           if ([self.delegate respondsToSelector:@selector(webSocketManagerDidReceiveMessageWithString:)]) {

               [self.delegate webSocketManagerDidReceiveMessageWithString:dataArray[0]];

           }

         NSLog(@"The message received was %@.",dataArray);

         NSString *dictStr = dataArray[0]; NSData *jsonData = [dictStr dataUsingEncoding:NSUTF8StringEncoding]; NSError *err; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];  [PushHandle shareHandle].webSocketInfoDic= dic;// The message sent by the server that needs to be processed.

       }];

    [self.socket on:@"sendHeartbeatMsg" callback:^(NSArray * _Nonnull dataArray, SocketAckEmitter * _Nonnull emitter) {

       

        NSLog(@"Received 💗");

    }];

     [self.socket on:@"disconnect" callback:^(NSArray * _Nonnull dataArray, SocketAckEmitter * _Nonnull emitter) {

         NSLog(@"Disconnect %@",dataArray);

     }];
   }
Copy the code

By listening for the corresponding message type, the corresponding message callback. The main logic processing is done in sendMsg, and the general type is shown in the figure above.

  • clsoeSocketClose long connection
// Close the persistent connection

- (void)RMWebSocketClose{

    self.isActivelyClose = YES;

    self.isConnect = NO;

    self.connectType = WebSocketDefault;

    if(self.socket)

    {

        [self.socket disconnect];

        _manger = nil;

        _socket = nil;

    }

    

    // Disable the heartbeat timer

    [self destoryHeartBeat];

    

    // Disable the network detection timer

    [self destoryNetWorkStartTesting];

}
Copy the code
  • keepHeartbeatSend a heartbeat
// Send the heartbeat

- (void)senderheartBeat{

    // Do you agree with the server what to send as a heartbeat identifier

    WS(weakSelf);

    dispatch_main_async_safe(^{

        if(weakSelf.socket.status == 3){ [weakSelf sendPing:nil]; }}); } - (void)sendPing:(id)sender{

    [self.socket emit:@"keepHeartbeat" with: [@ @"hello"]];

}
#pragma mark - NSTimer

\


// Initialize the heartbeat

- (void)initHeartBeat{

    // The heartbeat is not shut down

    if(self.heartBeatTimer) {

        return;

    }

    [self destoryHeartBeat];

    dispatch_main_async_safe(^{

        self.heartBeatTimer  = [NSTimer timerWithTimeInterval:55 target:self selector:@selector(senderheartBeat) userInfo:nil repeats:true]; [[NSRunLoop currentRunLoop]addTimer:self.heartBeatTimer forMode:NSRunLoopCommonModes]; })}Copy the code

The main initialization timer, and the background specifies how often to send the message type is keepHeartbeat, sent through the emit, sending the message is also acceptable.

  • Break line reconnection
// Reconnect

- (void)reConnectServer{

    if(self.socket.status == 3) {return;

    }

    

    if(self.reConnectTime > 1024) {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.socket.status == 3 && weakSelf.socket.status == 2) {

            return;

        }

        

        [weakSelf connectServer];

        // CTHLog(@" reconnecting to......") );

        

        if(weakSelf.reConnectTime == 0) {// Reconnection time 2 grows exponentially

            weakSelf.reConnectTime = 2;

        }else{

            weakSelf.reConnectTime *= 2; }}); }// Start timing when there is no network -- for network detection

- (void)noNetWorkStartTestingTimer{

    WS(weakSelf);

    dispatch_main_async_safe(^{

        weakSelf.netWorkTestingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(noNetWorkStartTesting) userInfo:nil repeats:YES];

        [[NSRunLoop currentRunLoop] addTimer:weakSelf.netWorkTestingTimer forMode:NSDefaultRunLoopMode];

    });

}

// Check the network periodically

- (void)noNetWorkStartTesting{

    / / a network

    if(AFNetworkReachabilityManager.sharedManager.networkReachabilityStatus ! = AFNetworkReachabilityStatusNotReachable) {// Disable the network detection timer

        [self destoryNetWorkStartTesting];

        // Start reconnecting[self reConnectServer]; }}// Cancel network detection

- (void)destoryNetWorkStartTesting{

    WS(weakSelf);

    dispatch_main_async_safe(^{

        if(weakSelf.netWorkTestingTimer) { [weakSelf.netWorkTestingTimer invalidate]; weakSelf.netWorkTestingTimer = nil; }}); }Copy the code

3. Summary

For socket.io-client-swif, we encapsulate a singleton class so that we can call it globally. The integration of socket.io-client-SWIF in OC project is mainly to initialize SocketManager and SocketIOClient to connect, listen for messages, send messages or heartbeat, and pay attention to the reconnection mechanism.