AsyncSocket 的使用

1、AsyncSocket

  • 基于 CFSocket、GCD 进行的封装(OC)。

  • 支持 TCP 和 UDP。

  • 完整的回调函数(用于处理各种回调事件,连接成功,断开连接,收到数据等)。

  • 需要注意的问题:

    • 1、Socekt 连接成功回调方法中主动调用:[self.socket readDataWithTimeout:-1 tag:0];,相当于主动添加一个读取请求,不然不会执行读取信息回调方法。
    • 2、读取信息回调方法中,读取完信息后,主动调用一下 [self.socket readDataWithTimeout:-1 tag:0];,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。

2、基本使用

2.1 Client 客户端

  • TCP 客户端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    #import "GCDAsyncSocket.h"

    @interface ViewController () <GCDAsyncSocketDelegate>

    @property (weak, nonatomic) IBOutlet UITextField *addrTF;
    @property (weak, nonatomic) IBOutlet UITextField *portTF;

    @property (weak, nonatomic) IBOutlet UITextField *msgTF;
    @property (weak, nonatomic) IBOutlet UITextView *logTV;

    @property (nonatomic, strong) GCDAsyncSocket *clientSockfd;

    @end

    @implementation ViewController

    - (void)viewDidLoad {
    [super viewDidLoad];

    // 创建 Socket,在主队列中处理,所有的回执都在主队列中执行
    self.clientSockfd = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }

    - (IBAction)connectBtnClick:(id)sender {

    NSError *error = nil;

    // Socket 连接
    if (![self.clientSockfd isConnected]) {
    [self.clientSockfd connectToHost:_addrTF.text onPort:_portTF.text.intValue error:&error];
    }

    if (error != nil) {
    [self showLogMessage:@"连接失败..."];
    }
    }

    #pragma mark - GCDAsyncSocketDelegate 协议方法

    // 连接成功,协议方法
    - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {

    // 读取数据,必须添加,相当于主动添加一个读取请求,不然不会执行读取信息回调方法
    [self.clientSockfd readDataWithTimeout:-1 tag:0];

    [self showLogMessage:[NSString stringWithFormat:@"连接服务器地址:%@, 端口:%d 成功", host, port]];
    [self showLogMessage:[NSString stringWithFormat:@"本地地址:%@, 端口:%d", sock.localHost, sock.localPort]];
    }

    // 已经断开链接,协议方法
    - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {

    [self showLogMessage:@"socket 断开连接..."];
    }

    // 读取到数据,协议方法
    - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {

    // 注意:要想长连接,必须还要在 DidReceiveData 的 delegate 中再写一次 [_udpSocket receiveOnce:&error]

    // 读取数据,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。
    [self.clientSockfd readDataWithTimeout:-1 tag:0];

    NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    [self showLogMessage:[NSString stringWithFormat:@"recv:%@", strMsg]];
    }

    #pragma mark - 发送数据

    - (IBAction)sendBtnClick:(id)sender {

    // Socket 发送数据
    [self.clientSockfd writeData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];

    [self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];
    }

    // 显示信息
    - (void)showLogMessage:(NSString *)msg {

    _logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];
    }

    // 键盘回收
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
    }

    @end

2.2 Server 服务端

  • TCP 服务端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    #import <arpa/inet.h>
    #import <ifaddrs.h>

    #import "GCDAsyncSocket.h"

    @interface ViewController () <GCDAsyncSocketDelegate>

    @property (weak, nonatomic) IBOutlet UITextField *addrTF;
    @property (weak, nonatomic) IBOutlet UITextField *portTF;

    @property (weak, nonatomic) IBOutlet UITextField *msgTF;
    @property (weak, nonatomic) IBOutlet UITextView *logTV;

    @property (nonatomic, strong) GCDAsyncSocket *serverSocketfd;
    @property (nonatomic, strong) GCDAsyncSocket *clientSocketfd;

    @end

    @implementation ViewController

    - (void)viewDidLoad {
    [super viewDidLoad];

    NSString *ip_addr = [self getIPAddress];
    _addrTF.text = ip_addr;

    // 创建 Socket,在主队列中处理,所有的回执都在主队列中执行
    self.serverSocketfd = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }

    - (IBAction)listenBtnClick:(id)sender {

    NSError *error = nil;

    // Socket 监听
    [self.serverSocketfd acceptOnPort:_portTF.text.intValue error:&error];

    if (error != nil) {
    NSLog(@"监听出错:%@", error);
    } else{
    [self showLogMessage:@"正在监听..."];
    }
    }

    #pragma mark - GCDAsyncSocketDelegate 协议方法

    // 接收到连接请求,协议方法
    - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {

    // 读取数据,必须添加,相当于主动添加一个读取请求,不然不会执行读取信息回调方法
    [newSocket readDataWithTimeout:-1 tag:0];

    [self showLogMessage:@"收到客户端连接...."];
    [self showLogMessage:[NSString stringWithFormat:@"客户端地址:%@, 端口:%d", newSocket.connectedHost, newSocket.connectedPort]];

    self.clientSocketfd = newSocket;
    }

    // 已经断开链接,协议方法
    - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {

    [self showLogMessage:@"socket 断开连接..."];
    }

    // 读取到数据,协议方法
    - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {

    // 读取数据,读取完信息后,重新向队列中添加一个读取请求,不然当收到信息后不会执行读取回调方法。
    [sock readDataWithTimeout:-1 tag:0];

    NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    [self showLogMessage:[NSString stringWithFormat:@"recv:%@",strMsg]];
    }

    #pragma mark - 发送数据

    - (IBAction)sendBtnClick:(id)sender {

    // Socket 发送数据
    [self.clientSocketfd writeData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];

    [self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];
    }

    #pragma mark - 获取本地 IP 地址

    - (NSString *)getIPAddress {

    NSString *address = @"error";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 0;

    // retrieve the current interfaces - returns 0 on success
    success = getifaddrs(&interfaces);

    if (success == 0) {

    // Loop through linked list of interfaces
    temp_addr = interfaces;

    while (temp_addr != NULL) {

    if (temp_addr->ifa_addr->sa_family == AF_INET) {

    // Check if interface is en0 which is the wifi connection on the iPhone
    if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {

    // Get NSString from C String
    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
    }
    }
    temp_addr = temp_addr->ifa_next;
    }
    }

    // Free memory
    freeifaddrs(interfaces);
    return address;
    }

    // 显示信息
    - (void)showLogMessage:(NSString *)msg {

    _logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];
    }

    // 键盘回收
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
    }

    @end

2.3 UDP 通信

  • UDP 通信

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    #import <arpa/inet.h>
    #import <ifaddrs.h>

    #import "GCDAsyncUdpSocket.h"

    @interface ViewController () <GCDAsyncUdpSocketDelegate>

    @property (weak, nonatomic) IBOutlet UITextField *desAddrTF;
    @property (weak, nonatomic) IBOutlet UITextField *desPortTF;

    @property (weak, nonatomic) IBOutlet UITextField *locAddrTF;
    @property (weak, nonatomic) IBOutlet UITextField *locPortTF;

    @property (weak, nonatomic) IBOutlet UITextField *msgTF;
    @property (weak, nonatomic) IBOutlet UITextView *logTV;

    @property (nonatomic, strong) GCDAsyncUdpSocket *udpSocketfd;

    @end

    @implementation ViewController

    - (void)viewDidLoad {
    [super viewDidLoad];

    NSString *ip_addr = [self getIPAddress];
    _locAddrTF.text = ip_addr;

    // 创建 Socket,在主队列中处理,所有的回执都在主队列中执行
    self.udpSocketfd = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }

    - (IBAction)connectBtnClick:(id)sender {

    NSError *error = nil;

    // 绑定端口
    [self.udpSocketfd bindToPort:_locPortTF.text.intValue error:&error];

    if (error != nil) {
    NSLog(@"绑定端口出错:%@", error);
    return;
    } else{
    [self showLogMessage:[NSString stringWithFormat:@"绑定端口 %d 成功...", _locPortTF.text.intValue]];
    }

    // 开始接收数据
    [self.udpSocketfd beginReceiving:&error];

    if (error != nil) {
    NSLog(@"开始接收数据出错:%@", error);
    } else{
    [self showLogMessage:@"开始接收数据..."];
    }
    }

    #pragma mark - GCDAsyncUdpSocketDelegate 协议方法

    // 接收到的数据,协议方法
    - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
    fromAddress:(NSData *)address
    withFilterContext:(id)filterContext {

    NSString *strMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    [self showLogMessage:[NSString stringWithFormat:@"recv:%@", strMsg]];
    }

    #pragma mark - 发送数据

    - (IBAction)sendBtnClick:(id)sender {

    // Socket 发送数据
    [self.udpSocketfd sendData:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding]
    toHost:_desAddrTF.text
    port:_desPortTF.text.intValue
    withTimeout:30 tag:0];

    [self showLogMessage:[NSString stringWithFormat:@"send:%@", _msgTF.text]];
    }

    #pragma mark - 获取本地 IP 地址

    - (NSString *)getIPAddress {

    NSString *address = @"error";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 0;

    // retrieve the current interfaces - returns 0 on success
    success = getifaddrs(&interfaces);

    if (success == 0) {

    // Loop through linked list of interfaces
    temp_addr = interfaces;

    while (temp_addr != NULL) {

    if (temp_addr->ifa_addr->sa_family == AF_INET) {

    // Check if interface is en0 which is the wifi connection on the iPhone
    if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {

    // Get NSString from C String
    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
    }
    }
    temp_addr = temp_addr->ifa_next;
    }
    }

    // Free memory
    freeifaddrs(interfaces);
    return address;
    }

    // 显示信息
    - (void)showLogMessage:(NSString *)msg {

    _logTV.text = [_logTV.text stringByAppendingFormat:@"%@\n", msg];
    }

    // 键盘回收
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
    }

    @end

2.4 Socket 长连接

  • PublicTool.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @interface PublicTool : NSObject

    // 字典转换成 JSON 字符串
    + (NSString *)JSONStringWithDic:(NSDictionary *)dic;

    // JSON 字符串转换成字典
    + (NSDictionary *)dictionaryWithJSON:(NSString *)json;

    @end
  • PublicTool.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    @implementation PublicTool

    // 字典转成成 JSON 字符串
    + (NSString *)JSONStringWithDic:(NSDictionary *)dic {

    NSError *error = nil;

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic
    options:0
    error:&error];

    if (jsonData == nil) {
    NSLog(@"fail to get JSON from dictionary: %@, error: %@", self, error);

    return nil;
    }
    NSString *jsonString = [[NSString alloc] initWithData:jsonData
    encoding:NSUTF8StringEncoding];

    return jsonString;
    }

    // JSON 字符串转换成字典
    + (NSDictionary *)dictionaryWithJSON:(NSString *)json {

    NSError *error = nil;

    NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];

    NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData
    options:NSJSONReadingMutableContainers |
    NSJSONReadingAllowFragments
    error:&error];

    if (jsonDict == nil) {
    NSLog(@"fail to get dictioanry from JSON: %@, error: %@", json, error);

    return nil;
    }

    return jsonDict;
    }

    @end
  • SocketSingleTon.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @interface SocketSingleTon : NSObject

    @property (nonatomic, copy) NSString *hostAddr;
    @property (nonatomic, copy) NSString *port;

    @property (nonatomic, copy) void(^msgLog)(NSString *);

    + (instancetype)shareInstance;

    // 连接到服务器
    - (void)connectToServer;

    // 断开连接
    - (void)cutOffSocket;

    // 发送数据到服务器
    - (void)sendDataToServer:(NSData*)data;

    @end
  • SocketSingleTon.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    #import "GCDAsyncSocket.h"
    #import <netdb.h>
    #import <arpa/inet.h>

    #import "PublicTool.h"

    typedef NS_ENUM(NSInteger, SocketOffline) {
    SocketOfflineByServer,
    SocketOfflineByUser
    };

    @interface SocketSingleTon () <GCDAsyncSocketDelegate>

    @property (nonatomic, strong) GCDAsyncSocket *socket;

    @property (nonatomic, strong) NSTimer *beatTimer;

    @end

    @implementation SocketSingleTon

    + (instancetype)shareInstance {

    static SocketSingleTon *shareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    shareInstance = [[self alloc] init];
    });
    return shareInstance;
    }

    // 连接到服务器
    - (void)connectToServer {

    NSError *error = nil;

    if (self.socket != nil) {

    if ([self.socket isConnected]) {

    // 断开后再连接
    self.socket.userData = @(SocketOfflineByUser);
    [self cutOffSocket];

    [self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];

    } else {

    [self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];
    }

    } else {
    self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

    [self.socket connectToHost:self.hostAddr onPort:self.port.intValue error:&error];
    }

    if (error != nil) {
    NSLog(@"socket 连接失败:%@", error);
    } else {
    NSLog(@"socket 连接成功");
    }
    }

    // 断开连接
    - (void)cutOffSocket {

    self.socket.userData = @(SocketOfflineByUser);
    [self.socket disconnect];
    }

    #pragma mark - GCDAsyncSocketDelegate 协议方法

    // 连接成功,协议方法
    - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {

    [sock readDataWithTimeout:-1 tag:0];

    NSString *logStr = [NSString stringWithFormat:@"连接主机:%@:%d 成功\n", host, port];
    NSLog(@"%@", logStr);

    if (self.msgLog) {
    self.msgLog(logStr);
    }

    // 创建定时器,定时发送 beat 包
    self.beatTimer = [NSTimer scheduledTimerWithTimeInterval:5
    target:self
    selector:@selector(longConnectToServer)
    userInfo:nil
    repeats:YES];
    }

    // 连接断开,协议方法
    - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {

    self.socket = nil;

    [self.beatTimer invalidate];
    self.beatTimer = nil;

    if ([sock.userData isEqual: @(SocketOfflineByUser)]) {

    NSLog(@"the socket have been cutted off by user");

    if (self.msgLog) {
    self.msgLog(@"the socket have been cutted off by user");
    }

    } else if (sock.userData == SocketOfflineByServer) {

    NSLog(@"the socket have been cutted off by server");

    if (self.msgLog) {
    self.msgLog(@"the socket have been cutted off by server");
    }

    // reconnect
    [self connectToServer];

    } else {

    NSLog(@"%@", err.localizedDescription);

    if (self.msgLog) {
    self.msgLog([NSString stringWithFormat:@"%@", err.localizedDescription]);
    }

    [self connectToServer];
    }
    }

    // 收到消息,协议方法
    - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {

    [sock readDataWithTimeout:-1 tag:0];

    char buf[1024];
    [data getBytes:buf length:1024];

    NSString *receivedData = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
    NSLog(@"receivedData:%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

    if (receivedData.length > 0) {

    NSDictionary *dataDic = [PublicTool dictionaryWithJSON:receivedData];

    if ([dataDic[@"msgType"] isEqualToString:@"beta"]) {
    NSString *strMsg = [NSString stringWithFormat:@"收到心跳确认的数据:%@\n", receivedData];
    if (self.msgLog) {
    self.msgLog(strMsg);
    }
    } else if ([dataDic[@"msgType"] isEqualToString:@"normal"]) {
    NSString *strMsg = [NSString stringWithFormat:@"收到正常的数据:%@\n", receivedData];
    if (self.msgLog) {
    self.msgLog(strMsg);
    }
    } else if ([dataDic[@"msgType"] isEqualToString:@"exit"]) {
    NSString *strMsg = [NSString stringWithFormat:@"收到关闭的数据:%@\n", receivedData];
    if (self.msgLog) {
    self.msgLog(strMsg);
    }
    [self cutOffSocket];
    }
    }
    }

    // 发送数据
    - (void)longConnectToServer {
    [self sendDataToServer:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
    }

    // 发送数据到服务器
    - (void)sendDataToServer:(NSData*)data {

    NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSMutableDictionary *dicParams = [NSMutableDictionary dictionary];

    if ([dataStr isEqualToString:@"hello"]) {
    [dicParams setValue:dataStr forKey:@"msg"];
    [dicParams setValue:@"beta" forKey:@"msgType"];
    } else {
    [dicParams setValue:dataStr forKey:@"msg"];
    [dicParams setValue:@"normal" forKey:@"msgType"];
    }

    NSData *sendData = [[PublicTool JSONStringWithDic:dicParams] dataUsingEncoding:NSUTF8StringEncoding];

    NSString *strMsg = [NSString stringWithFormat:@"发送数据: %@\n", [PublicTool JSONStringWithDic:dicParams]];
    if (self.msgLog) {
    self.msgLog(strMsg);
    }

    [self.socket writeData:sendData withTimeout:30 tag:0];
    }

    @end
  • ViewController.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    #import "SocketSingleTon.h"
    #import "PublicTool.h"

    @interface ViewController ()

    @property (weak, nonatomic) IBOutlet UITextField *addressTF;
    @property (weak, nonatomic) IBOutlet UITextField *portTF;

    @property (weak, nonatomic) IBOutlet UITextField *msgTF;
    @property (weak, nonatomic) IBOutlet UITextView *logTV;

    @end

    @implementation ViewController

    - (IBAction)connectToServer:(id)sender {

    // 创建 Socket
    SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];

    socketInstance.hostAddr = _addressTF.text;
    socketInstance.port = _portTF.text;

    __weak __typeof (self)weakSelf = self;
    socketInstance.msgLog = ^(NSString *log){

    dispatch_async(dispatch_get_main_queue(), ^{
    weakSelf.logTV.text = [weakSelf.logTV.text stringByAppendingString:log];
    });
    };

    // 连接到服务器
    [socketInstance connectToServer];
    }

    - (IBAction)cutOffConnect:(id)sender {

    SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];

    // 断开连接
    [socketInstance cutOffSocket];
    }

    - (IBAction)sendDataToServer:(id)sender {

    SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];

    // 发送数据到服务器
    [socketInstance sendDataToServer:[_msgTF.text dataUsingEncoding:NSUTF8StringEncoding]];
    }

    - (IBAction)sendBetaDataToServer:(id)sender {

    SocketSingleTon *socketInstance = [SocketSingleTon shareInstance];

    NSMutableDictionary *dicParams = [NSMutableDictionary dictionary];
    [dicParams setValue:@"beta" forKey:@"msgType"];
    [dicParams setValue:@"hello" forKey:@"msg"];
    NSString *strMsg = [PublicTool JSONStringWithDic:dicParams];

    // 发送心跳数据到服务器
    [socketInstance sendDataToServer:[strMsg dataUsingEncoding:NSUTF8StringEncoding]];
    }

    - (IBAction)clearLog:(id)sender {
    _logTV.text = nil;
    }

    // 键盘回收
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
    }

    @end

文章目录
  1. 1. 1、AsyncSocket
  2. 2. 2、基本使用
    1. 2.1. 2.1 Client 客户端
    2. 2.2. 2.2 Server 服务端
    3. 2.3. 2.3 UDP 通信
    4. 2.4. 2.4 Socket 长连接
隐藏目录