iOS Socket(2) —— BSDSocket的使用

BSDSocket

BSDSocket是UNIX的Socket框架,iOS的系统内核便是UNIX,Xcode可以直接使用BSDSocket

BSDSocket 的函数

  • 创建Socket:

int socket(int domain, int type, int protocol)

  • domain: 协议族,例如:AF_INET(ipv4),AF_INET6(ipv6)
  • type:Socket 类型,例如:SOCK_STREAM(流式/TCP),SOCK_DGRAM (数据报式/UDP)
  • protocol:指定协议,例如:IPPROTO_TCP(TCP 传输协议),IPPROTO_UDP(UDP 传输协议),当protocol = 0 时,更加type参数自动选择类型
  • 返回值:如果调用成功就返回新创建的套接字的描述符(大于 0),如果失败就返回 INVALID_SOCKET(Linux 下失败返回 -1)
  • 绑定ip 地址 + 端口

int bind(int sockfd, const struct sockaddr * addr, socklen_t addrlen)

  • sockfd :套接字描述符,就是上面socket()的返回值
  • addr :是一个 sockaddr 结构指针,该结构中包含了要结合的地址和端口号
  • addrlen:addr 的长度
  • 返回值:如果函数执行成功,返回值为 0,否则为 -1
  • 监听端口

int listen(int sockfd, int backlog)

  • sockfd :套接字描述符
  • backlog:socket 可以排队连接的最大数
  • 返回值:如果函数执行成功,返回值为 0,否则为 -1
  • 接受连接

int accept(int sockfd, struct sockaddr * addr, socklen_t * addrlen)

  • sockfd :监听套接字描述符
  • addr :返回客户端的地址
  • addrlen:addr 的长度
  • 返回值:成功返回由内核自动生成的一个全新的描述符(即连接成功的客户端的套接字描述符),失败返回 -1
  • 连接

int connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen)

  • sockfd :套接字描述符
  • addr :指定数据发送的目的地,也就是服务器端的地址
  • addrlen:addr 的长度
  • 返回值:如果函数执行成功,返回值为 0,否则为 -1
  • 断开连接

int close(int sockfd)

  • sockfd :套接字描述符
  • 返回值:如果函数执行成功,返回值为 0,否则为 -1
  • 发送数据

ssize_t write(int sockfd, const void * buf, size_t size)

  • sockfd:套接字描述符
  • buf :发送内容地址,message.UTF8String 将字符串转换成 UTF8 的 ASCII 码,一个汉字需要 3 个字节
  • size :发送内容长度,是字节的个数,需使用 strlen() 计算所有字节的长度
  • 返回值:如果成功,则返回发送的字节数,失败则返回 -1,并设置 error 变量。 如果错误为 EINTR 表示在写的时候出现了中断错误。如果为 EPIPE 表示网络连接出现了问题(对方已经关闭了连接)

ssize_t send(int sockfd, const void * buf, size_t size, int flags)

  • sockfd:套接字描述符
  • buf :发送内容地址,message.UTF8String 将字符串转换成 UTF8 的 ASCII 码,一个汉字需要 3 个字节
  • size :发送内容长度,是字节的个数,需使用 strlen() 计算所有字节的长度
  • 返回值:如果成功,则返回发送的字节数,失败则返回 -1

ssize_t sendto(int sockfd, const void * buf, size_t size, int flags, const struct sockaddr * dest_addr, socklen_t addrlen)

  • sockfd :套接字描述符
  • buf :待发送数据的缓冲区
  • size :缓冲区长度,是字节的个数,需使用 strlen() 计算所有字节的长度
  • flags :调用方式标志位, 一般为 0, 改变 Flags,将会改变 Sendto 发送的形式
  • dest_addr:可选指针,指向目的套接字的地址
  • addrlen :dest_addr 的长度
  • 返回值:如果成功,则返回发送的字节数,失败则返回 -1

ssize_t sendmsg(int sockfd, const struct msghdr * msg, int flags)

  • sockfd:套接字描述符
  • msg :送数据的内容
  • flags :调用方式标志位
  • 返回值:如果成功,则返回发送的字节数,失败则返回 -1
  • 接受数据

ssize_t read(int sockfd, void * buf, size_t size)

  • sockfd:套接字描述符
  • buf :用于接收数据的缓冲区
  • size :缓冲区长度
  • 返回值:如果成功,返回实际所读的字节数,如果返回的值是 0 表示已经读到文件的结束了,小于 0 表示出现了错误。 如果错误为 EINTR 说明读是由中断引起的,如果是 ECONNREST 表示网络连接出了问题

ssize_t recv(int sockfd, void * buf, size_t size, int flags)

  • sockfd:套接字描述符
  • buf :用于接收数据的缓冲区
  • size :缓冲区长度
  • flags :指定调用方式,MSG_PEEK:查看当前数据,数据将被复制到缓冲区中,但并不从输入队列中删除;MSG_OOB :指示接收到 out-of-band 数据(即需要优先处理的数据)
  • 返回值:如果成功,返回实际所读的字节数,如果返回的值是 0 表示已经读到文件的结束了,小于 0 表示出现了错误

ssize_t recvfrom(int sockfd, void * buf, size_t size, int flags, struct sockaddr * src_addr, socklen_t * addrlen)

ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags)

  • sockfd:套接字描述符
  • buf :用于接收数据的缓冲区
  • size :缓冲区长度
  • 返回值: 如果成功,返回实际所读的字节数,如果返回的值是 0 表示已经读到文件的结束了,小于 0 表示出现了错误

ssize_t recvfrom(int sockfd, void * buf, size_t size, int flags, struct sockaddr * src_addr, socklen_t * addrlen);

  • sockfd :套接字描述符
  • buf :接收数据缓冲区
  • size :缓冲区长度
  • flags :调用操作方式。是以下一个或者多个标志的组合体,可通过 or 操作连在一起: MSG_DONTWAIT:操作不会被阻塞 MSG_ERRQUEUE:指示应该从套接字的错误队列上接收错误值,依据不同的协议,错误值以某种辅佐性消息的方式传递进来, 使用者应该提供足够大的缓冲区。导致错误的原封包通过 msg_iovec 作为一般的数据来传递。导致错误 的数据报原目标地址作为 msg_name 被提供。错误以 sock_extended_err 结构形态被使用 MSG_PEEK :指示数据接收后,在接收队列中保留原数据,不将其删除,随后的读操作还可以接收相同的数据 MSG_TRUNC :返回封包的实际长度,即使它比所提供的缓冲区更长, 只对 packet 套接字有效 MSG_WAITALL :要求阻塞操作,直到请求得到完整的满足。然而,如果捕捉到信号,错误或者连接断开发生,或者下次被 接收的数据类型不同,仍会返回少于请求量的数据 MSG_EOR :指示记录的结束,返回的数据完成一个记录 MSG_CTRUNC :指明由于缓冲区空间不足,一些控制数据已被丢弃 MSG_OOB :指示接收到 out-of-band 数据(即需要优先处理的数据) MSG_ERRQUEUE:指示除了来自套接字错误队列的错误外,没有接收到其它数据
  • src_addr:可选指针,指向装有源地址的缓冲区
  • addrlen :可选指针,指向 address 缓冲区长度值
  • 返回值: 如果成功,返回实际所读的字节数,如果返回的值是 0 表示已经读到文件的结束了,小于 0 表示出现了错误。
  • 其他
struct sockaddr_in {
        __uint8_t       sin_len;            // 地址长度
        sa_family_t     sin_family;         // IP 地址协议族,必须设为 AF_INET
        in_port_t       sin_port;           // 通信端口
        struct in_addr  sin_addr;           // 以网络字节排序的 4 字节 IPv4 地址
        char            sin_zero[8];        // 填充项,是为了让 sockaddr 与 sockaddr_in 两个数据结构保持大小相同而保留的空字节
    };

    struct sockaddr {
        __uint8_t       sa_len;             // 地址长度
        sa_family_t     sa_family;          // IP 地址协议族,必须设为 AF_INET
        char            sa_data[14];        // 地址值
    };

    struct in_addr {
        uint32_t        s_addr;             // 按照网络字节顺序存储 IP 地址
    };

        sockaddr_in 和 sockaddr 是并列的结构,指向 sockaddr_in 的结构体的指针也可以指向 sockaddr 的结构体,并代替它。
    也就是说,你可以使用 sockaddr_in 建立你所需要的信息。
复制代码
struct sockaddr_in address;

    // 清空内存
    memset(&address, 0, sizeof(address));                     // 清空指向的内存中的存储内容,因为分配的内存是随机的,
                                                              // 如果不清空可能会因为垃圾数据产生不必要的麻烦
    bzero(& address, sizeof(address));                        // 清空指向的内存中的存储内容

    // 设置地址值
    ser_addr.sin_len        = sizeof(address);                // 地址长度
    address.sin_family      = AF_INET;                        // 协议族
    address.sin_port        = htons(12345);                   // 端口数据高位在前低位在后 12345 => 3039 => 3930
    address.sin_addr.s_addr = inet_addr("192.168.88.100");    // inet_addr 函数可以把 ip 地址转换成一个整数

    // 设置所有地址值
    address.sin_addr.s_addr = INADDR_ANY;                     // 指定地址为 0.0.0.0 的地址,这个地址事实上表示不确定地址,
                                                              // 或所有地址、所有 ip、任意地址。一般来说,在各个系统中均定义成为 0 值

    // 获取地址值
    int ip_port   = ntohs(address.sin_port);                  // 获取端口,如获取到:53746
    char *ip_addr = inet_ntoa(address.sin_addr);              // 获取 IP 地址,如获取到:192.168.88.100

    // 获取本地地址
    socklen_t addrLen = sizeof(address);
    getsockname(self.clientSockfd, (struct sockaddr *)&address, &addrLen);
    int ip_port   = ntohs(address.sin_port);                  // 本地端口
    char *ip_addr = inet_ntoa(address.sin_addr);              // 本地 IP 地址
复制代码

实践

  1. iOS中使用BSDSocket,首先要引入头文件:
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <ifaddrs.h>

复制代码
  1. 创建服务端,我使用的是Mac界面开发。
#import "ViewController.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
@interface ViewController ()
{
    NSInteger _protocolIndex;//0:TCP,1:UDP
    NSString *_loc_ipAdr,*_loc_port,*_des_ipAdress,*_des_port;
    int _tcp_serverSockfd,_udp_serverSockfd;//服务端套接字描述符
    int _clientSockfd;//客户端端套接字描述符
    int _errCode;//绑定时的返回值
    
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _loc_ipAdr = @"127.0.0.1";
    _loc_port = @"10000";
    
    _des_ipAdress = [self getIPAddress];
    _des_port = @"10001";
    [NSThread detachNewThreadSelector:@selector(creatTCPSocket) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(creatUDPSocket) toTarget:self withObject:nil];
    // Do any additional setup after loading the view.
}

#pragma mark - 创建Socket
- (void)creatTCPSocket{
    
   _tcp_serverSockfd  = socket(AF_INET, SOCK_STREAM, 0);
    if (_tcp_serverSockfd > 0 ) {
        NSLog(@"TCP socket创建成功");
        [self TCPBind];
    }else {
        NSLog(@"TCP socket创建失败");
        
    }
}

- (void)creatUDPSocket{
    _udp_serverSockfd  = socket(AF_INET, SOCK_DGRAM, 0);
    if (_udp_serverSockfd > 0 ) {
        NSLog(@"UDP socket创建成功");
        [self UDPBind];
    }else {
        NSLog(@"UDP socket创建失败");
        
    }
}


#pragma mark - 绑定IP地址和端口号

- (void)TCPBind {
    //获取本地地址
    struct sockaddr_in loc_addr;
    //清空指向的内存中的存储内容,因为分配的内存是随机的
    memset(&loc_addr, 0, sizeof(loc_addr));
//    loc_addr.sin_len = sizeof(struct sockaddr_in);
    //设置协议族
    loc_addr.sin_family = AF_INET;
    //设置端口
    loc_addr.sin_port = htons(_loc_port.intValue);
    //设置IP地址
    loc_addr.sin_addr.s_addr = inet_addr(_loc_ipAdr.UTF8String);
    //绑定
    _errCode = bind(_tcp_serverSockfd, (const struct sockaddr *)&loc_addr,sizeof(loc_addr) );
    if (_errCode == 0) {
        NSLog(@"TCP socket绑定成功");
        [self listen];
        
    }else {
        NSLog(@"TCP socekt绑定失败");
        
    }
    
    
  
    
}
- (void)UDPBind {
    //获取本地地址
    struct sockaddr_in loc_addr;
    //清空指向的内存中的存储内容,因为分配的内存是随机的
    memset(&loc_addr, 0, sizeof(loc_addr));
    //    loc_addr.sin_len = sizeof(struct sockaddr_in);
    //设置协议族
    loc_addr.sin_family = AF_INET;
    //设置端口
    loc_addr.sin_port = htons(_loc_port.intValue);
    //设置IP地址
    loc_addr.sin_addr.s_addr = inet_addr(_loc_ipAdr.UTF8String);
    //绑定
    int udpCode = bind(_udp_serverSockfd, (const struct sockaddr *)&loc_addr,sizeof(loc_addr) );
    
    if (udpCode == 0) {
        NSLog(@"UDP socket绑定成功");
        [self UDPRecv];
        
    }else{
        NSLog(@"UDP socekt绑定失败");
        
    }
}
#pragma mark - 监听、阻塞等待客服端的连接请求、接收消息

- (void)listen {
    _errCode = listen(_tcp_serverSockfd, 9);//9:最大连接个数
    
    if (_errCode == 0) {
        NSLog(@"socket监听成功");
        //使用循环,持续监听
        while (YES) {
            //连接的客户端的地址
            struct sockaddr_in client_addr;
            socklen_t cli_addr_len = sizeof(client_addr);
            //阻塞等待客服端的连接请求
            _clientSockfd = accept(_tcp_serverSockfd, (struct sockaddr *)&client_addr, &cli_addr_len);
            if (_clientSockfd != -1) {
                //连接成功
                NSLog(@"socket连接成功");

            }
            //创建一个字符串接收
            char buf[1024];
            do {
                // 返回读取的字节数
                ssize_t recvLen = recv(_clientSockfd, buf, sizeof(buf), 0);
                
                if (recvLen > 0) {
                    NSString *recvStr = [NSString stringWithFormat:@"[TCP消息][来自客户端%@:%@]:%@",_des_ipAdress,_des_port, [NSString stringWithUTF8String:buf]];
                    NSLog(@"%@",recvStr);
                    dispatch_async(dispatch_get_main_queue(), ^{
                        self->_recTextView.string = recvStr;
                    });
                    
                }
                
            } while (strcmp(buf, "exit") != 0);
        }
        
        
    }else {
        NSLog(@"socekt监听失败");
        
    }
}

#pragma mark - UDP接收
- (void)UDPRecv{
    // 目标地址
    struct sockaddr_in des_addr;
    bzero(&des_addr, sizeof(des_addr));
    des_addr.sin_family      = AF_INET;
    des_addr.sin_port        = htons(_des_port.intValue);
    des_addr.sin_addr.s_addr = inet_addr(_des_ipAdress.UTF8String);
    
    char buf[1024];
    //清空指向的内存中的存储内容
    bzero(buf, sizeof(buf));
    
    while(1) {
        
        // 接收数据
        socklen_t des_addr_len = sizeof(des_addr);
        ssize_t recvLen = recvfrom(_udp_serverSockfd, buf, sizeof(buf), 0, (struct sockaddr*)&des_addr, &des_addr_len);
        
        if (recvLen > 0) {
            NSString *recvStr = [NSString stringWithFormat:@"[UDP消息][来自客户端%@:%@]:%@",_des_ipAdress,_des_port, [NSString stringWithUTF8String:buf]];
            NSLog(@"%@",recvStr);

            dispatch_async(dispatch_get_main_queue(), ^{
                self->_recTextView.string = recvStr;
            });
        }
    }
}



#pragma mark - 发送
- (IBAction)sendMsg:(id)sender {
    if (!self.textInput.stringValue.length) {
        return;
    }
    
    NSString *sendMsg = self.textInput.stringValue;
    
    ssize_t sendLen = 0;
    if (_protocolIndex == 0) {
        
        // 发送数据
        sendLen = send(_clientSockfd, sendMsg.UTF8String, strlen(sendMsg.UTF8String), 0);
        
    }
    
    if (_protocolIndex == 1) {
        
        // 发送数据
        // 目标地址
        struct sockaddr_in des_addr;
        bzero(&des_addr, sizeof(des_addr));
        des_addr.sin_family      = AF_INET;
        des_addr.sin_port        = htons(_des_port.intValue);
        des_addr.sin_addr.s_addr = inet_addr(_des_ipAdress.UTF8String);
        
        // 发送数据
        sendLen = sendto(_udp_serverSockfd, sendMsg.UTF8String, strlen(sendMsg.UTF8String), 0,
                         (struct sockaddr *)&des_addr, sizeof(des_addr));
        
    }
    
    if (sendLen > 0) {
        NSLog(@"发送成功");
    }else{
        NSLog(@"发送失败");
    }
}
#pragma mark - 选择协议
- (IBAction)choseProtocol:(NSComboBox *)sender {
    if ([sender.stringValue isEqualToString:@"TCP"]) {
        NSLog(@"选择TCP");
        _protocolIndex = 0;

    }
    if ([sender.stringValue isEqualToString:@"UDP"]) {
        NSLog(@"选择UDP");
        _protocolIndex = 1;

    }

    
}

- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];

    // Update the view, if already loaded.
}


#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;
}

复制代码
  1. 创建客户端
#import "ViewController.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
@interface ViewController (){
    NSInteger _protocolIndex;//0:TCP,1:UDP
    int _tcp_clientSockfd,_udp_clientSockfd;//客户端端套接字描述符
    NSString *_loc_ipAdr,*_loc_port,*_des_ipAdress,*_des_port;

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

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _loc_ipAdr = [self getIPAddress];
    _loc_port = @"10001";
    
    _des_ipAdress = @"127.0.0.1";
    _des_port = @"10000";
    [self chose:self.segmentControl];
    
    [NSThread detachNewThreadSelector:@selector(creatTCPSocket) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(creatUDPSocket) toTarget:self withObject:nil];

    // Do any additional setup after loading the view, typically from a nib.
}

#pragma mark - 创建Socket
- (void)creatTCPSocket{
    
    _tcp_clientSockfd  = socket(AF_INET, SOCK_STREAM, 0);
    if (_tcp_clientSockfd > 0 ) {
        NSLog(@"TCP socket创建成功");
        [self connect];
        
    }else {
        NSLog(@"TCP socket创建失败");
        
    }
}

- (void)creatUDPSocket{
    
    _udp_clientSockfd  = socket(AF_INET, SOCK_DGRAM, 0);
    if (_udp_clientSockfd > 0 ) {
        NSLog(@"UDP socket创建成功");
        
        [self UDPRecv];

        
    }else {
        NSLog(@"UDP socket创建失败");
        
    }
}

#pragma mark - 连接服务器

- (void)connect {
    //获取服务器地址
    struct sockaddr_in des_addr;
    //清空指向的内存中的存储内容,因为分配的内存是随机的
    memset(&des_addr, 0, sizeof(des_addr));
    //设置协议族
    des_addr.sin_family = AF_INET;
    //设置端口
    des_addr.sin_port = htons(_des_port.intValue);
    //设置IP地址
    des_addr.sin_addr.s_addr = inet_addr(_des_ipAdress.UTF8String);
    //连接
    
    int errCode = connect(_tcp_clientSockfd, (struct sockaddr *)&des_addr, sizeof(des_addr));
    
    if (errCode == 0) {
        NSLog(@"socket连接成功");
        [self TCPRecv];
        
    }else {
        NSLog(@"socekt连接失败");
        
    }
    
}

#pragma mark - TCP接收
- (void)TCPRecv {
    char buf[1024];
    do {
        // 接收数据
        ssize_t recvLen = recv(_tcp_clientSockfd, buf, sizeof(buf), 0);
        
        if (recvLen > 0) {
            NSString *recvStr = [NSString stringWithFormat:@"[TCP消息][来自服务端%@:%@]:%@",_des_ipAdress,_des_port, [NSString stringWithUTF8String:buf]];
            NSLog(@"%@",recvStr);
            dispatch_async(dispatch_get_main_queue(), ^{
                self->_recvTextView.text = recvStr;
            });
        }
        
    } while (strcmp(buf, "exit") != 0);
}

#pragma mark - UDP接收

- (void)UDPRecv {
    // 本地地址
    struct sockaddr_in loc_addr;
    bzero(&loc_addr, sizeof(loc_addr));
    loc_addr.sin_port        = htons(_loc_port.intValue);
    loc_addr.sin_addr.s_addr = inet_addr(_loc_ipAdr.UTF8String);
    // 绑定
    int err = bind(_udp_clientSockfd, (const struct sockaddr *)&loc_addr, sizeof(loc_addr));
    
    if (err != 0) {
        NSLog(@"socket 绑定失败");
        
    } else {
        
        NSLog(@"socket 绑定成功");
        // 目标地址
        struct sockaddr_in des_addr;
        bzero(&des_addr, sizeof(des_addr));
        des_addr.sin_family      = AF_INET;
        des_addr.sin_port        = htons(_des_port.intValue);
        des_addr.sin_addr.s_addr = inet_addr(_des_ipAdress.UTF8String);
        
        char buf[256];
        bzero(buf, sizeof(buf));
        
        while(1) {
            
            // 接收数据
            socklen_t des_addr_len = sizeof(des_addr);
            ssize_t recvLen = recvfrom(_udp_clientSockfd, buf, sizeof(buf), 0, (struct sockaddr*)&des_addr, &des_addr_len);
            
            if (recvLen > 0) {
                NSString *recvStr = [NSString stringWithFormat:@"[UDP消息][来自服务端%@:%@]:%@",_des_ipAdress,_des_port, [NSString stringWithUTF8String:buf]];
                NSLog(@"%@",recvStr);
                dispatch_async(dispatch_get_main_queue(), ^{
                    self->_recvTextView.text = recvStr;
                });
            }
        }
    }
    
}



- (IBAction)send:(id)sender {
    
    if (!self.sendTF.text.length) {
        return;
    }
    
    ssize_t sendLen = 0;
    if (_protocolIndex == 0) {
        
        // 发送数据
        sendLen = send(_tcp_clientSockfd, _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0);
        
    }
    
    if (_protocolIndex == 1) {
        
        // 发送数据
        // 目标地址
        struct sockaddr_in des_addr;
        bzero(&des_addr, sizeof(des_addr));
        des_addr.sin_family      = AF_INET;
        des_addr.sin_port        = htons(_des_port.intValue);
        des_addr.sin_addr.s_addr = inet_addr(_des_ipAdress.UTF8String);
        
        // 发送数据
        sendLen = sendto(_udp_clientSockfd, _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0,
                         (struct sockaddr *)&des_addr, sizeof(des_addr));
        
    }
    
    if (sendLen > 0) {
        NSLog(@"发送成功");
    }else{
        NSLog(@"发送失败");
    }
    
    
}

- (IBAction)chose:(UISegmentedControl *)sender {
    
    _protocolIndex = sender.selectedSegmentIndex;
    
    if (sender.selectedSegmentIndex == 0) {
        NSLog(@"选择TCP");
   
    }
    if (sender.selectedSegmentIndex == 1) {
        NSLog(@"选择UDP");
    }
}

#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;
}



@end

复制代码

Demo

  • 下载地址:github.com/namesubai/S…
  • 请先编译服务端SocketDemoMac项目,再编译客户端SocketDemoMac项目
  • Demo界面效果截图

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值