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 失败...\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); 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 连接失败...\n";
    [self showMessage:logStr]; return; } else { logStr = [NSString stringWithFormat:@"socket 连接 %@ 成功...\n", _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:%@\n", [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\n");
    } else {
    NSLog(@"connect success\n");
    }
    } #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:%@\n", _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];
    }

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 失败...\n";
    [self showMessage:logStr]; return; } else { logStr = @"创建 socket 成功...\n";
    [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 绑定失败...\n";
    [self showMessage:logStr]; CFRelease(self.serverSockfd);
    self.serverSockfd = NULL; return; } else { logStr = @"socket 绑定成功...\n";
    [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\n", 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:%@\n", [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:%@\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];
    });
    } // 键盘回收
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
    }

iOS - CFSocket 的使用的更多相关文章

  1. iOS面试用到的知识点和技术点--第二章

    接着第一章的继续  昨天没有更新,很抱歉 1.Socket编程 以及一些第三方框架Socket-IO GCDAsyncSocket通信框架? 1.使用系统自带的CFsocket 2.第三方Socket ...

  2. iOS面试题汇总

    摘要:1. Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么? 答: Object-c的类不可以多重继承;可以实现多个接口,通 ...

  3. iOS开发中对RunLoop的个人心得

    从接触iOS到现在也有将近两年了,对iOS中的RunLoop也有了一定的认识,下面讲讲个人对RunLoop的理解.   初识RunLoop RunLoops是与线程相关联的基础部分,一个Run Loo ...

  4. iOS中多线程原理与runloop介绍

    一.线程概述 有些程序是一条直线,起点到终点:有些程序是一个圆,不断循环,直到将它切断.直线的如简单的Hello World,运行打印完,它的生命周期便结束了,像昙花一现那样:圆如操作系统,一直运行直 ...

  5. iOS网络编程模型

    iOS网络编程层次结构也分为三层: Cocoa层:NSURL,Bonjour,Game Kit,WebKit Core Foundation层:基于 C 的 CFNetwork 和 CFNetServ ...

  6. 直接拿来用!最火的iOS开源项目

    1. AFNetworking 在众多iOS开源项目中,AFNetworking可以称得上是最受开发者欢迎的库项目.AFNetworking是一个轻量级的iOS.Mac OS X网络通信类库,现在是G ...

  7. 超全!iOS 面试题汇总

    之前看了很多面试题,感觉要不是不够就是过于冗余,于是我将网上的一些面试题进行了删减和重排,现在分享给大家.(题目来源于网络,侵删) 1. Object-c的类可以多重继承么?可以实现多个接口么?Cat ...

  8. iOS多线程介绍

    一.线程概述 有些程序是一条直线,起点到终点:有些程序是一个圆,不断循环,直到将它切断.直线的如简单的Hello World,运行打印完,它的生命周期便结束了,像昙花一现那样:圆如操作系统,一直运行直 ...

  9. IOS socket开发基础

    摘要 详细介绍了iOS的socket开发,说明了tcp和udp的区别,简单说明了tcp的三次握手四次挥手,用c语言分别实现了TCPsocket和UDPsocket的客户端和服务端,本文的作用是让我们了 ...

随机推荐

  1. 混沌数学之Rössler(若斯叻)吸引子

    若斯叻吸引子(Rössler attractor)是一组三元非线性微分方程: frac{dx(t)}{dt} = -y(t)-z(t) frac{dy(t)}{dt} = x(t)+a*y(t) fr ...

  2. Why游戏作品合集

    之前曾经发过一个套WhyEngine游戏作品合集,里面有十几个小游戏和若干个屏保程序和若干个DEMO程序.而这次发的与上次不一样,因为这是我花了两天时间将所有的程序集成到一个工程后的成果.为了能将所有 ...

  3. 第十二章 ThreadPoolExecutor使用 + 工作机理 + 生命周期

    1.最基础的线程池ThreadPoolExecutor 使用方式: /** * ThreadPoolExecutor测试类 * 注意: * 1.ThreadPoolExecutor是一个线程池 * 2 ...

  4. 安装Oracle之后解决掉的问题分享

    TNS-03505: 无法解析名称                                                            在测试tnsping的时候始终显示这么个问题. ...

  5. shapefile文件的符号化问题

    我们都知道,ArcGIS的shp文件只以坐标形式保存地图数据,地图的显示方法则是存储都数据库或地图文件(mxd)中,这一点是深信不疑的. 如果我们打开ArcMap,新建一个普通的地图文件(使用标准的模 ...

  6. WPF 同一个程序 只允许 同时运行一个

            方法2  当程序已经运行了 再运行这个程序时,则显示当前这个窗体  http://code.3rbang.com/cshape-run-one/ VS2013附件:http://fil ...

  7. Android的startActivityForResult不起作用

    之前startActivityForResult一直用的好好的,今天发现怎么也不起作用.检查后发现有两点影响了. 1.android:launchMode="singleTask" ...

  8. jquery局部打印插件使用

    基于jquery库的jquery.PrintArea.js插件源代码为: (function ($) { var printAreaCount = 0; $.fn.printArea = functi ...

  9. nyoj阶乘之和

     /*阶乘之和 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描写叙述 给你一个非负数整数n,推断n是不是一些数(这些数不同意反复使用,且为正数)的阶乘之和, 如9=1! ...

  10. SPOJ 74. Divisor Summation 分解数字的因子

    本题有两个难点: 1 大量的数据输入.没处理好就超时 - 这里使用buffer解决 2 因子分解的算法 a)暴力法超时 b)使用sieve(筛子),只是当中的算法逻辑也挺不easy搞对的. 数值N因子 ...