BSDSocket 的使用

1、BSDSocket

  • 一套 unix 系统下的 socket API(纯 C)。

  • iOS 系统基于 unix,所以支持底层的 BSD Socket,在 Xcode 中可以直接使用。

2、基本使用

2.1 Client 客户端

  • TCP 客户端

    • 包含头文件

      1
      2
      3
      4
      #import <sys/socket.h>
      #import <netinet/in.h>
      #import <arpa/inet.h>
      #import <ifaddrs.h>
    • 创建 Socket

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      // client Socket
      @property (nonatomic, assign) int clientSocket;

      self.clientSocket = socket(AF_INET, SOCK_STREAM, 0);

      if (self.clientSocket > 0) {
      NSLog(@"Socket 创建成功 %d", self.clientSocket);
      } else {
      NSLog(@"Socket 创建失败");
      }
    • 连接到服务器

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      // 创建服务器地址结构体
      struct sockaddr_in serverAddress;
      bzero(&serverAddress, sizeof(serverAddress));
      serverAddress.sin_family = AF_INET; // 协议族
      serverAddress.sin_port = htons(12345); // 端口 端口数据高位在前低位在后 12345 => 3039 => 3930
      serverAddress.sin_addr.s_addr = inet_addr("192.168.88.100"); // inet_addr 函数可以把 ip 地址转换成一个整数

      int isConnected = connect(self.clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress));

      if (isConnected) {
      NSLog(@"连接失败 %d", isConnected);
      } else {
      NSLog(@"连接成功");
      }
    • 发送数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      NSString *message = @"你好";

      ssize_t sendLen = send(self.clientSocket, message.UTF8String, strlen(message.UTF8String), 0);

      if (sendLen > 0) {
      NSLog(@"发送成功,发送 %ld 个字节数据", sendLen);
      } else {
      NSLog(@"发送失败 %zd", sendLen);
      }
    • 接收数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      // 接收字符串的数组,typedef unsigned char uint8_t;
      uint8_t buffer[1024];

      ssize_t recvLen = recv(self.clientSocket, buffer, sizeof(buffer), 0);

      if (recvLen > 0) {

      // 按照服务器返回的长度,从 buffer 中,读取二进制数据,建立 NSData 对象
      NSData *data = [NSData dataWithBytes:buffer length:recvLen];
      NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

      NSLog(@"接收成功,接收到 %ld 个字节数据\n 接收到:%@", recvLen, str);
      } else {
      NSLog(@"接收失败 %zd", recvLen);
      }
    • 关闭连接

      1
      2
      3
      4
      // 数据传递完毕之后,关闭连接
      int isCloseed = close(self.clientSocket);

      NSLog(@"%d", isCloseed);

2.2 Server 服务端

  • TCP 服务端

    • 包含头文件

      1
      2
      3
      4
      #import <sys/socket.h>
      #import <netinet/in.h>
      #import <arpa/inet.h>
      #import <ifaddrs.h>
    • 创建 Socket

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      // server Socket
      @property (nonatomic, assign) int serverSocket;

      // client Socket
      @property (nonatomic, assign) int clientSocket;

      self.serverSocket = socket(AF_INET, SOCK_STREAM, 0);

      if (self.serverSocket > 0) {
      NSLog(@"Socket 创建成功 %d", self.serverSocket);
      } else {
      NSLog(@"Socket 创建失败");
      }
    • 开始监听

      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
      // 创建服务器地址结构体
      struct sockaddr_in serverAddress;
      bzero(&serverAddress, sizeof(serverAddress));
      serverAddress.sin_family = AF_INET;
      serverAddress.sin_port = htons(12345);
      serverAddress.sin_addr.s_addr = inet_addr("192.168.88.100");

      int isBind = bind(self.serverSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress));

      if (isBind) {
      NSLog(@"绑定失败 %d", isBind);
      return;
      } else {
      NSLog(@"绑定成功");
      }

      int isListen = listen(self.serverSocket, 10);

      if (isListen) {
      NSLog(@"监听失败 %d", isListen);
      return;
      } else {
      NSLog(@"监听成功");
      }

      // clientSocket
      struct sockaddr_in clientAddress;
      bzero(&clientAddress, sizeof(clientAddress));
      socklen_t len = sizeof(clientAddress);

      self.clientSocket = accept(self.serverSocket, (struct sockaddr *)&clientAddress, &len);

      if (self.clientSocket) {
      NSLog(@"接收成功 %d,client IP:%zd", self.clientSocket, clientAddress);
      } else {
      NSLog(@"接收失败");
      }
    • 发送数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      NSString *message = @"你好";

      // 使用 clientSocket
      ssize_t sendLen = send(self.clientSocket, message.UTF8String, strlen(message.UTF8String), 0);

      if (sendLen > 0) {
      NSLog(@"发送成功,发送 %ld 个字节数据", sendLen);
      } else {
      NSLog(@"发送失败 %zd", sendLen);
      }
    • 接收数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      // 接收字符串的数组,typedef unsigned char uint8_t;
      uint8_t buffer[1024];

      // 使用 clientSocket
      ssize_t recvLen = recv(self.clientSocket, buffer, sizeof(buffer), 0);

      if (recvLen > 0) {

      // 按照服务器返回的长度,从 buffer 中,读取二进制数据,建立 NSData 对象
      NSData *data = [NSData dataWithBytes:buffer length:recvLen];
      NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

      NSLog(@"接收成功,接收到 %ld 个字节数据\n 接收到:%@", recvLen, str);
      } else {
      NSLog(@"接收失败 %zd", recvLen);
      }
    • 关闭连接

      1
      2
      3
      4
      // 数据传递完毕之后,关闭连接
      int isCloseed = close(self.serverSocket);

      NSLog(@"%d", isCloseed);

3、网络访问

  • 1、请求:

    • 1)请求行

      • GET / HTTP/1.1

      • 方法 GET

      • 路径 /
      • 协议 HTTP 1.1
    • 2)请求头

      • Host: localhost 主机
      • User-Agent: 告诉服务器客户端的类型
      • Accept: 告诉服务器客户端支持的格式
      • Accept-Language: 告诉服务器客户端的语言
      • Accept-Encoding: 告诉服务器客户端支持的压缩格式
  • 2、响应:

    • 1)状态行

      • HTTP/1.1 200 OK

        • 协议 HTTP 1.1
        • 状态码:
          • 200 成功
          • 404 页面没找到
          • 301 内容没变化,用在缓存
    • 2)响应头(主要在开发下载应用的时候使用的)

      • Date: Tue, 24 Mar 2015 01:52:25 GMT 访问日期
      • Server: Apache/2.4.9 (Unix) 访问服务器的类型
      • Content-Location: index.html.en 访问的文件名
      • Content-Length: 45 访问文件的大小
      • Content-Type: text/html 访问文件的类型
    • 3)数据实体

      • <html><body><h1>It works!</h1></body></html>

      • 访问服务器最需的,相当于 NSURLConnection 异步方法回调中的 data。

  • 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
    // 包含头文件
    #import <sys/socket.h>
    #import <netinet/in.h>
    #import <arpa/inet.h>
    #import <ifaddrs.h>

    @property (nonatomic, assign) int clientSocket;

    - (void)socketHttpRequest {

    // 连接到服务器,80 端口 apache 中就是 http 的协议
    if (![self connection:@"127.0.0.1" port:80]) {
    return;
    }

    // 创建请求
    NSString *requestStr = @"GET / HTTP/1.1\n"
    "Host: localhost\n"
    "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:36.0) Gecko/20100101 Firefox/36.0\n"
    "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n"
    "Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3\n"

    // \n 拼接换行,内容由 firefox 浏览器的网络控制面板的原始请求头信息中复制
    "Accept-Encoding: gzip, deflate\n"

    // 删除最后三行,最后一行加两个 \n\n
    "Connection: keep-alive\n\n";

    // 发送接收请求,发送给 web 服务器的请求需要遵守 http 协议
    NSString *recvStr = [self sendAndRecv:requestStr];

    NSLog(@"%@", recvStr);
    }

    /// 创建连接
    - (BOOL)connection:(NSString *)hostText port:(int)port {

    // 创建 Socket

    self.clientSocket = socket(AF_INET, SOCK_STREAM, 0);

    // 连接到服务器

    struct sockaddr_in serverAddress;
    bzero(&serverAddress, sizeof(serverAddress));
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(port);
    serverAddress.sin_addr.s_addr = inet_addr(hostText.UTF8String);

    int isConnected = connect(self.clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress));

    return (isConnected == 0);
    }

    /// 发送和接收字符串
    - (NSString *)sendAndRecv:(NSString *)message {

    // 发送数据

    send(self.clientSocket, message.UTF8String, strlen(message.UTF8String), 0);

    // 接收数据

    uint8_t buffer[1024];

    ssize_t recvLen = recv(self.clientSocket, buffer, sizeof(buffer), 0);

    NSData *data = [NSData dataWithBytes:buffer length:recvLen];
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    return str;
    }

4、客户端使用

  • TCP 客户端 & 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
    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
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    // 包含头文件
    #import <sys/socket.h>
    #import <netinet/in.h>
    #import <arpa/inet.h>
    #import <ifaddrs.h>

    typedef NS_ENUM (NSInteger,ServerType) {
    ServerTypeTCP,
    ServerTypeUDP
    };

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

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

    @property (weak, nonatomic) IBOutlet UITextView *recvTextView;
    @property (weak, nonatomic) IBOutlet UITextField *sendTF;

    @property (nonatomic, assign) int clientSockfd;
    @property (nonatomic, assign) int udpSockfd;

    @property (nonatomic, assign) ServerType serType;

    - (void)viewDidLoad {
    [super viewDidLoad];

    NSString *ip_addr = [self getIPAddress];
    _locIPTF.text = ip_addr;
    }

    #pragma mark - 创建 TCP 连接

    - (IBAction)connectTCPServer:(id)sender {

    [NSThread detachNewThreadSelector:@selector(connectTCPSer) toTarget:self withObject:nil];
    }

    - (void)connectTCPSer {

    self.serType = ServerTypeTCP;

    BOOL success;
    int err;

    // 创建 socket
    self.clientSockfd = socket(AF_INET, SOCK_STREAM, 0);
    success = (self.clientSockfd != -1);

    NSString *logStr = nil;

    if (success == NO) {

    logStr = @"创建 socket 失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"创建 socket 成功...\n";
    [self showMessage:logStr];

    // 服务器地址
    struct sockaddr_in ser_addr;
    memset(&ser_addr, 0, sizeof(ser_addr));
    ser_addr.sin_len = sizeof(ser_addr);
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(_desPortTF.text.intValue);
    ser_addr.sin_addr.s_addr = inet_addr(_desIPTF.text.UTF8String);

    // 连接
    err = connect(self.clientSockfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
    success = (err == 0);
    }

    if (success == NO) {

    logStr = @"socket 连接失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = [NSString stringWithFormat:@"socket 连接 %@ 成功...\n", _desIPTF.text];
    [self showMessage:logStr];

    char buf[1024];
    do {
    // 接收数据
    ssize_t recvLen = recv(self.clientSockfd, buf, sizeof(buf), 0);

    if (recvLen > 0) {
    logStr = [NSString stringWithFormat:@"recv:%@\n", [NSString stringWithUTF8String:buf]];
    [self showMessage:logStr];
    }

    } while (strcmp(buf, "exit") != 0);
    }
    }

    #pragma mark - 创建 UDP 连接

    - (IBAction)connectUDP:(id)sender {

    [NSThread detachNewThreadSelector:@selector(connectUDP) toTarget:self withObject:nil];
    }

    - (void)connectUDP {

    self.serType = ServerTypeUDP;

    BOOL success;
    int err;

    // 创建 Socket
    self.udpSockfd = socket(AF_INET, SOCK_DGRAM, 0);
    success = (self.udpSockfd != -1);

    NSString *logStr = nil;

    if (success == NO) {

    logStr = @"创建 socket 失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"创建 socket 成功...\n";
    [self showMessage:logStr];

    // 本地地址
    struct sockaddr_in loc_addr;
    bzero(&loc_addr, sizeof(loc_addr));
    loc_addr.sin_port = htons(_locPortTF.text.intValue);
    loc_addr.sin_addr.s_addr = inet_addr(_locIPTF.text.UTF8String);

    // 绑定
    err = bind(self.udpSockfd, (const struct sockaddr *)&loc_addr, sizeof(loc_addr));
    success = (err == 0);
    }

    if (success == NO) {

    logStr = @"socket 绑定失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"socket 绑定成功...\n";
    [self showMessage:logStr];

    // 目标地址
    struct sockaddr_in des_addr;
    bzero(&des_addr, sizeof(des_addr));
    des_addr.sin_family = AF_INET;
    des_addr.sin_port = htons(_desPortTF.text.intValue);
    des_addr.sin_addr.s_addr = inet_addr(_desIPTF.text.UTF8String);

    char buf[256];
    bzero(buf, sizeof(buf));

    while(1) {

    // 接收数据
    socklen_t des_addr_len = sizeof(des_addr);
    ssize_t recvLen = recvfrom(self.udpSockfd, buf, sizeof(buf), 0, (struct sockaddr*)&des_addr, &des_addr_len);

    if (recvLen > 0) {
    logStr = [NSString stringWithFormat:@"recv:%@\n", [NSString stringWithUTF8String:buf]];
    [self showMessage:logStr];
    }
    }
    }
    }

    #pragma mark - 发送数据

    - (IBAction)btnClick:(id)sender {

    if (_sendTF.text.length == 0) {
    return;
    } else {

    ssize_t sendLen;

    if (self.serType == ServerTypeTCP) {

    // 发送数据
    sendLen = send(self.clientSockfd, _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0);

    } else if (self.serType == ServerTypeUDP) {

    // 目标地址
    struct sockaddr_in des_addr;
    bzero(&des_addr, sizeof(des_addr));
    des_addr.sin_family = AF_INET;
    des_addr.sin_port = htons(_desPortTF.text.intValue);
    des_addr.sin_addr.s_addr = inet_addr(_desIPTF.text.UTF8String);

    // 发送数据
    sendLen = sendto(self.udpSockfd, _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0,
    (struct sockaddr *)&des_addr, sizeof(des_addr));
    }

    if (sendLen > 0) {
    NSString *logStr = [NSString stringWithFormat:@"send:%@\n", _sendTF.text];
    [self showMessage:logStr];
    }
    }
    }

    #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)showMessage:(NSString *)msg {

    dispatch_async(dispatch_get_main_queue(), ^{

    _recvTextView.text = [_recvTextView.text stringByAppendingString:msg];
    });
    }

5、服务端使用

  • TCP 服务端 & 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
    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
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    // 包含头文件
    #import <sys/socket.h>
    #import <netinet/in.h>
    #import <arpa/inet.h>
    #import <ifaddrs.h>

    typedef NS_ENUM (NSInteger,ServerType) {
    ServerTypeTCP,
    ServerTypeUDP
    };

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

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

    @property (weak, nonatomic) IBOutlet UITextView *recvTextView;
    @property (weak, nonatomic) IBOutlet UITextField *sendTF;

    @property (nonatomic, assign) int serverSockfd;
    @property (nonatomic, assign) int clientSockfd;

    @property (nonatomic, assign) int udpSockfd;

    @property (nonatomic, assign) ServerType serType;

    - (void)viewDidLoad {
    [super viewDidLoad];

    NSString *ip_addr = [self getIPAddress];
    _locIPTF.text = ip_addr;
    }

    #pragma mark - 创建 TCP 监听

    - (IBAction)createdTCPServer:(id)sender {

    _desIPTF.enabled = NO;
    _desPortTF.enabled = NO;
    _locPortTF.enabled = NO;

    [NSThread detachNewThreadSelector:@selector(createdTCPSer) toTarget:self withObject:nil];
    }

    - (void)createdTCPSer {

    self.serType = ServerTypeTCP;

    BOOL success;
    int err;

    // 创建 socket
    self.serverSockfd = socket(AF_INET, SOCK_STREAM, 0);
    success = (self.serverSockfd != -1);

    NSString *logStr = nil;

    if (success == NO) {

    logStr = @"创建 socket 失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"创建 socket 成功...\n";
    [self showMessage:logStr];

    // 本地地址
    struct sockaddr_in loc_addr;
    memset(&loc_addr, 0, sizeof(loc_addr));
    loc_addr.sin_family = AF_INET;
    loc_addr.sin_port = htons(_locPortTF.text.intValue);
    loc_addr.sin_addr.s_addr = inet_addr(_locIPTF.text.UTF8String);

    // 绑定
    err = bind(self.serverSockfd, (const struct sockaddr *)&loc_addr, sizeof(loc_addr));
    success = (err == 0);
    }

    if (success == NO) {

    logStr = @"socket 绑定失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"socket 绑定成功...\n";
    [self showMessage:logStr];

    // 监听
    err = listen(self.serverSockfd, 5); // 5:最大连接个数
    success = (err == 0);
    }

    if (success == NO) {

    logStr = @"socket 监听失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"socket 监听成功...\n";
    [self showMessage:logStr];

    while (true) { // 循环

    // 连接的客户端的地址
    struct sockaddr_in cli_addr;
    socklen_t cli_addr_Len = sizeof(cli_addr);

    // 接受客户端的请求,并建立连接
    self.clientSockfd = accept(self.serverSockfd, (struct sockaddr *)&cli_addr, &cli_addr_Len);
    success = (self.clientSockfd != -1);

    if (success) {

    char *ip_addr = inet_ntoa(cli_addr.sin_addr);
    int ip_port = ntohs(cli_addr.sin_port);
    dispatch_async(dispatch_get_main_queue(), ^{
    _desIPTF.text = [NSString stringWithFormat:@"%s", ip_addr];
    _desPortTF.text = [NSString stringWithFormat:@"%d", ip_port];
    });

    logStr = [NSString stringWithFormat:@"已连接:%s,port:%d\n", ip_addr, ip_port];
    [self showMessage:logStr];

    char buf[1024];
    do {
    // 返回读取的字节数
    ssize_t recvLen = recv(self.clientSockfd, buf, sizeof(buf), 0);

    if (recvLen > 0) {
    logStr = [NSString stringWithFormat:@"recv:%@\n", [NSString stringWithUTF8String:buf]];
    [self showMessage:logStr];
    }

    } while (strcmp(buf, "exit") != 0);
    }
    }
    }
    }

    #pragma mark - 创建 UDP 连接

    - (IBAction)connectUDP:(id)sender {

    [NSThread detachNewThreadSelector:@selector(connectUDP) toTarget:self withObject:nil];
    }

    - (void)connectUDP {

    self.serType = ServerTypeUDP;

    BOOL success;
    int err;

    // 创建 Socket
    self.udpSockfd = socket(AF_INET, SOCK_DGRAM, 0);
    success = (self.udpSockfd != -1);

    NSString *logStr = nil;

    if (success == NO) {

    logStr = @"创建 socket 失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"创建 socket 成功...\n";
    [self showMessage:logStr];

    // 本地地址
    struct sockaddr_in loc_addr;
    bzero(&loc_addr, sizeof(loc_addr));
    loc_addr.sin_port = htons(_locPortTF.text.intValue);
    loc_addr.sin_addr.s_addr = inet_addr(_locIPTF.text.UTF8String);

    // 绑定
    err = bind(self.udpSockfd, (const struct sockaddr *)&loc_addr, sizeof(loc_addr));
    success = (err == 0);
    }

    if (success == NO) {

    logStr = @"socket 绑定失败...\n";
    [self showMessage:logStr];

    return;

    } else {

    logStr = @"socket 绑定成功...\n";
    [self showMessage:logStr];

    // 目标地址
    struct sockaddr_in des_addr;
    bzero(&des_addr, sizeof(des_addr));
    des_addr.sin_family = AF_INET;
    des_addr.sin_port = htons(_desPortTF.text.intValue);
    des_addr.sin_addr.s_addr = inet_addr(_desIPTF.text.UTF8String);

    char buf[256];
    bzero(buf, sizeof(buf));

    while(1) {

    // 接收数据
    socklen_t des_addr_len = sizeof(des_addr);
    ssize_t recvLen = recvfrom(self.udpSockfd, buf, sizeof(buf), 0, (struct sockaddr*)&des_addr, &des_addr_len);

    if (recvLen > 0) {
    logStr = [NSString stringWithFormat:@"recv:%@\n", [NSString stringWithUTF8String:buf]];
    [self showMessage:logStr];
    }
    }
    }
    }

    #pragma mark - 发送数据

    - (IBAction)btnClick:(id)sender {

    if (_sendTF.text.length == 0) {
    return;
    } else {

    ssize_t sendLen;

    if (self.serType == ServerTypeTCP) {

    // 发送数据
    sendLen = send(self.clientSockfd, _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0);

    } else if (self.serType == ServerTypeUDP) {

    // 目标地址
    struct sockaddr_in des_addr;
    bzero(&des_addr, sizeof(des_addr));
    des_addr.sin_family = AF_INET;
    des_addr.sin_port = htons(_desPortTF.text.intValue);
    des_addr.sin_addr.s_addr = inet_addr(_desIPTF.text.UTF8String);

    // 发送数据
    sendLen = sendto(self.udpSockfd, _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0,
    (struct sockaddr *)&des_addr, sizeof(des_addr));
    }

    if (sendLen > 0) {
    NSString *logStr = [NSString stringWithFormat:@"send:%@\n", _sendTF.text];
    [self showMessage:logStr];
    }
    }
    }

    #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)showMessage:(NSString *)msg {

    dispatch_async(dispatch_get_main_queue(), ^{

    _recvTextView.text = [_recvTextView.text stringByAppendingString:msg];
    });
    }

文章目录
  1. 1. 1、BSDSocket
  2. 2. 2、基本使用
    1. 2.1. 2.1 Client 客户端
    2. 2.2. 2.2 Server 服务端
  3. 3. 3、网络访问
  4. 4. 4、客户端使用
  5. 5. 5、服务端使用
隐藏目录