iOS

1、CFSocket

  • 苹果对对底层 BSD Socket 进行轻量级的封装(纯 C)。

  • 主要使用的 API:CFSocekt 用于建立连接,CFStream 用于读写数据。

2、基本使用

2.1 Client 客户端

  • TCP 客户端

    	// 包含头文件
    	#import <sys/socket.h>
    	#import <netinet/in.h>
    	#import <arpa/inet.h>
    	
    	@property (weak, nonatomic) IBOutlet UITextField *desIPTF;
    	@property (weak, nonatomic) IBOutlet UITextField *desPortTF;
    	
    	@property (weak, nonatomic) IBOutlet UITextView *recvTextView;
    	@property (weak, nonatomic) IBOutlet UITextField *sendTF;
    	
    	@property (nonatomic, assign) CFSocketRef clientSockfd;
    
    	#pragma mark - 创建 TCP 连接
    	
    	- (IBAction)connectTCPServer:(id)sender {
    	    
    	    [NSThread detachNewThreadSelector:@selector(connectTCPSer) toTarget:self withObject:nil];
    	}
    	
    	- (void)connectTCPSer {
    	    
    	    BOOL success;
    	    
    	    // 创建 socket
    	    self.clientSockfd = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketConnectCallBack, ServerConnectCallBack, NULL);
    	    success = (self.clientSockfd != nil);
    	    
    	    NSString *logStr = nil;
    	    
    	    if (success == NO) {
    	        
    	        logStr = @"创建 socket 失败...
    ";
    	        [self showMessage:logStr];
    	        
    	        return;
    	        
    	    } else {
    	        
    	        logStr = @"创建 socket 成功...
    ";
    	        [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);
    	        
    	        CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&ser_addr, sizeof((ser_addr)));
    	        
    	        // 连接
    	        CFSocketError result = CFSocketConnectToAddress(self.clientSockfd, address, 5);
    	        CFRelease(address);
    	        success = (result == kCFSocketSuccess);
    	    }
    	    
    	    if (success == NO) {
    	        
    	        logStr = @"socket 连接失败...
    ";
    	        [self showMessage:logStr];
    	        
    	        return;
    	        
    	    } else {
    	        
    	        logStr = [NSString stringWithFormat:@"socket 连接 %@ 成功...
    ", _desIPTF.text];
    	        [self showMessage:logStr];
    	        
    	        char buf[2048];
    	        do {
    	            // 接收数据
    	            ssize_t recvLen = recv(CFSocketGetNative(self.clientSockfd), buf, sizeof(buf), 0);
    	            
    	            if (recvLen > 0) {
    	                logStr = [NSString stringWithFormat:@"recv:%@
    ", [NSString stringWithFormat:@"%s", buf]];
    	                [self showMessage:logStr];
    	            }
    	            
    	        } while (strcmp(buf, "exit") != 0);
    	        
    	        CFRunLoopRef cfrl = CFRunLoopGetCurrent();
    	        CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.clientSockfd, 0);
    	        CFRunLoopAddSource(cfrl, source, kCFRunLoopCommonModes);
    	        CFRelease(source);
    	        CFRunLoopRun();
    	    }
    	}
    	
    	// 连接成功的回调函数
    	void ServerConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void * data, void *info) {
    	    
    	    if (data != NULL) {
    	        NSLog(@"connect
    ");
    	    } else {
    	        NSLog(@"connect success
    ");
    	    }
    	}
    	
    	#pragma mark - 发送数据
    	
    	- (IBAction)btnClick:(id)sender {
    	    
    	    if (_sendTF.text.length == 0) {
    	        return;
    	    } else {
    	        
    	        // 发送数据
    	        ssize_t sendLen = send(CFSocketGetNative(self.clientSockfd), _sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String), 0);
    	
    	        if (sendLen > 0) {
    	            NSString *logStr = [NSString stringWithFormat:@"send:%@
    ", _sendTF.text];
    	            [self showMessage:logStr];
    	        }
    	    }
    	}
    	
    	// 显示信息
    	- (void)showMessage:(NSString *)msg {
    	    
    	    dispatch_async(dispatch_get_main_queue(), ^{
    	        
    	        _recvTextView.text = [_recvTextView.text stringByAppendingString:msg];
    	    });
    	}
    	
    	// 键盘回收
    	- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    	    [self.view endEditing:YES];
    	}
    

    Socket8

2.2 Server 服务端

  • TCP 服务端

    	// 包含头文件
    	#import <sys/socket.h>
    	#import <netinet/in.h>
    	#import <arpa/inet.h>
    	#import <ifaddrs.h>
    	
    	static ViewController *selfClass = nil;
    	
    	@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) CFSocketRef serverSockfd;
    	
    	@property (nonatomic, assign) CFWriteStreamRef outputStream;
    
    	- (void)viewDidLoad {
    	    [super viewDidLoad];
    	    
    	    NSString *ip_addr = [self getIPAddress];
    	    _locIPTF.text = ip_addr;
    	    
    	    // 函数指针指向本身
    	    selfClass = self;
    	}
    	
    	#pragma mark - 创建 TCP 监听
    	
    	- (IBAction)createdTCPServer:(id)sender {
    	    
    	    [sender setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    	    
    	    [NSThread detachNewThreadSelector:@selector(createdTCPSer) toTarget:self withObject:nil];
    	}
    	
    	- (void)createdTCPSer {
    	    
    	    BOOL success;
    	    
    	    // 创建 socket
    	    self.serverSockfd = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, TCPServerAcceptCallBack, NULL);
    	    success = (self.serverSockfd != NULL);
    	    
    	    NSString *logStr = nil;
    	    
    	    if (success == NO) {
    	        
    	        logStr = @"创建 socket 失败...
    ";
    	        [self showMessage:logStr];
    	        
    	        return;
    	        
    	    } else {
    	        
    	        logStr = @"创建 socket 成功...
    ";
    	        [self showMessage:logStr];
    	        
    	        int optVal = 1;
    	        setsockopt(CFSocketGetNative(self.serverSockfd), SOL_SOCKET, SO_REUSEADDR, (void*)&optVal,sizeof(optVal));
    	        
    	        // 本地地址
    	        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);
    	        
    	        CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8*)&loc_addr, sizeof(loc_addr));
    	        
    	        // 绑定
    	        CFSocketError err = CFSocketSetAddress(self.serverSockfd, address);
    	        CFRelease(address);
    	        success = (err == kCFSocketSuccess);
    	    }
    	    
    	    if (success == NO) {
    	        
    	        logStr = @"socket 绑定失败...
    ";
    	        [self showMessage:logStr];
    	        
    	        CFRelease(self.serverSockfd);
    	        self.serverSockfd = NULL;
    	        
    	        return;
    	        
    	    } else {
    	        
    	        logStr = @"socket 绑定成功...
    ";
    	        [self showMessage:logStr];
    	        
    	        CFRunLoopRef cfRunloop = CFRunLoopGetCurrent();
    	        CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.serverSockfd, 0);
    	        CFRunLoopAddSource(cfRunloop, source, kCFRunLoopCommonModes);
    	        CFRelease(source);
    	        CFRunLoopRun();
    	    }
    	}
    	
    	// 客户端连接成功的回调函数
    	void TCPServerAcceptCallBack(CFSocketRef socket ,CFSocketCallBackType type,CFDataRef address,const void *data, void *info) {
    	    
    	    // 客户端连接
    	    if (kCFSocketAcceptCallBack == type) {
    	        
    	        // data  the handle of socket
    	        CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;
    	        
    	        uint8_t name[SOCK_MAXADDRLEN];
    	        socklen_t nameLen = sizeof(name);
    	        
    	        // 获取对方 socket 信息,还有 getsocketname() 函数用于获取本程序所在 socket 信息
    	        if (getpeername(nativeSocketHandle, (struct sockaddr *)name, &nameLen) != 0) {
    	            exit(1);
    	        }
    	        
    	        // 获取连接的客户端信息
    	        struct sockaddr_in * addr_in = (struct sockaddr_in *)name;
    	        char *ip_addr = inet_ntoa(addr_in->sin_addr);
    	        int ip_port   = addr_in->sin_port;
    	        
    	        NSString *logStr = [NSString stringWithFormat:@"已连接:%s,port:%d
    ", ip_addr, ip_port];
    	        [selfClass showMessage:logStr];
    	        
    	        // 创建一对输入输出流用于读写数据
    	        CFReadStreamRef iStream;
    	        CFWriteStreamRef oStream;
    	        
    	        // 创建一组可读/写的 CFStreame
    	        CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &iStream, &oStream);
    	        
    	        if (iStream && oStream) {
    	            
    	            // 打开输入流和输出流
    	            CFReadStreamOpen(iStream);
    	            CFWriteStreamOpen(oStream);
    	            
    	            CFStreamClientContext streamContext = {0, NULL, NULL, NULL};
    	            
    	            // if have data to read   call the readStream function
    	            if (!CFReadStreamSetClient(iStream, kCFStreamEventHasBytesAvailable, readStream, &streamContext)) {
    	                exit(1);
    	            }
    	            
    	            CFReadStreamScheduleWithRunLoop(iStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    	            
    	            selfClass.outputStream = oStream;
    	        }
    	    }
    	}
    	
    	// 读取数据的回调函数
    	void readStream(CFReadStreamRef iStream, CFStreamEventType eventType, void * clientCallBackInfo){
    	    
    	    char buf[2048];
    	    bzero(buf, sizeof(buf));
    	    
    	    do {
    	        // 接收数据
    	        CFIndex dex = CFReadStreamRead(iStream, (UInt8 *)buf, sizeof(buf));
    	        
    	        if (dex > 0) {
    	            NSString *logStr = [NSString stringWithFormat:@"recv:%@
    ", [NSString stringWithFormat:@"%s", buf]];
    	            [selfClass showMessage:logStr];
    	        }
    	        
    	    } while (strcmp(buf, "exit") != 0);
    	}
    	
    	#pragma mark - 发送数据
    	
    	- (IBAction)btnClick:(id)sender {
    	    
    	    if (_sendTF.text.length == 0) {
    	        return;
    	    } else {
    	        
    	        // 发送数据
    	        CFIndex dex = CFWriteStreamWrite(selfClass.outputStream, (UInt8 *)_sendTF.text.UTF8String, strlen(_sendTF.text.UTF8String)+1);
    	        
    	        if (dex > 0) {
    	            NSString *logStr = [NSString stringWithFormat:@"send:%@
    ", _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];
    	    });
    	}
    	
    	// 键盘回收
    	- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    	    [self.view endEditing:YES];
    	}
    

    Socket9

原文地址:https://www.cnblogs.com/QianChia/p/6391989.html