iOS开发攻城狮的集散地iOS Developer程序员

Socket简析与iOS实现

2018-05-04  本文已影响262人  无忌不悔
WebSocket

Socket的基本概念

1.定义

网络上两个程序通过一个双向通信连接实现数据交互,这种双向通信的连接叫做Socket(套接字)。

2.本质

网络模型中应用层与TCP/IP协议族通信的中间软件抽象层,是它的一组编程接口(API),也即对TCP/IP的封装。TCP/IP也要提供可供程序员做网络开发所用的接口,即Socket编程接口。

Socket的位置

3.要素

Socket是网络通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信的必须的五种信息:

4.特性

Socket可以支持不同的传输协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接;同理,当使用UDP协议进行连接时,该Socket连接就是一个UDP连接。
多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

5.连接

建立Socket连接至少需要一对套接字,分别运行于服务端(ServerSocket)和客户端(ClientSocket)。套接字直接的连接过程氛围三个步骤:

Step 1 服务器监听

服务端Socket始终处于等待连接状态,实时监听是否有客户端请求连接。

Step 2 客户端请求

客户端Socket提出连接请求,指定服务端Socket的地址和端口号,这时就可以向对应的服务端提出Socket连接请求。

Step 3 连接确认

当服务端Socket监听到客户端Socket提出的连接请求时作出响应,建立一个新的进程,把服务端Socket的描述发送给客户端,该描述得到客户端确认后就可建立起Socket连接。而服务端Socket则继续处于监听状态,继续接收其他客户端Socket的请求。

iOS客户端Socket的实现

1. 数据流方式

- (IBAction)connectToServer:(id)sender {
    // 1.与服务器通过三次握手建立连接
    NSString *host = @"192.168.1.58";
    int port = 1212;
    
    //创建一个socket对象
    _socket = [[GCDAsyncSocket alloc] initWithDelegate:self
                                         delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    
    NSError *error = nil;
    
    // 开始连接
    [_socket connectToHost:host
                    onPort:port
                     error:&error];
    
    if (error) {
        NSLog(@"%@",error);
    }
}


#pragma mark - Socket代理方法
// 连接成功
- (void)socket:(GCDAsyncSocket *)sock
didConnectToHost:(NSString *)host
          port:(uint16_t)port {
    NSLog(@"%s",__func__);
}


// 断开连接
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock
                  withError:(NSError *)err {
    if (err) {
        NSLog(@"连接失败");
    } else {
        NSLog(@"正常断开");
    }
}


// 发送数据
- (void)socket:(GCDAsyncSocket *)sock
didWriteDataWithTag:(long)tag {
    
    NSLog(@"%s",__func__);
    
    //发送完数据手动读取,-1不设置超时
    [sock readDataWithTimeout:-1
                          tag:tag];
}

// 读取数据
-(void)socket:(GCDAsyncSocket *)sock
  didReadData:(NSData *)data
      withTag:(long)tag {
    
    NSString *receiverStr = [[NSString alloc] initWithData:data
                                                  encoding:NSUTF8StringEncoding];
    
    NSLog(@"%s %@",__func__,receiverStr);
}

2.基于第三方开源库CocoaAsyncSocket

2.1客户端通过地址和端口号与服务端建立Socket连接,并写入相关数据。

- (void)connectToServerWithCommand:(NSString *)command
{
    _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
    [_socket setUserData:command];
    
    NSError *error = nil;
    [_socket connectToHost:WIFI_DIRECT_HOST onPort:WIFI_DIRECT_PORT error:&error];
    if (error) {
        NSLog(@"__connect error:%@",error.userInfo);
    }
    
    [_socket writeData:[command dataUsingEncoding:NSUTF8StringEncoding] withTimeout:10.0f tag:6];
}

2.2 实现CocoaAsyncSocket的代理方法

#pragma mark - Socket Delegate

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    NSLog(@"Socket连接成功:%s",__func__);
}

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    if (err) {
        NSLog(@"连接失败");
    }else{
        NSLog(@"正常断开");
    }
    
    if ([sock.userData isEqualToString:[NSString stringWithFormat:@"%d",SOCKET_CONNECT_SERVER]])
    {
        //服务器掉线 重新连接
        [self connectToServerWithCommand:@"battery"];
    }else
    {
        return;
    }
}

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    NSLog(@"数据发送成功:%s",__func__);
    //发送完数据手动读取,-1不设置超时
    [sock readDataWithTimeout:-1 tag:tag];
}

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"读取数据:%s %@",__func__,receiverStr);
}

粘包与半包

关于粘包和半包,请看iOS 详解Socket编程粘包、半包处理

上一篇下一篇

猜你喜欢

热点阅读