#import "ViewController.h" #import <sys/socket.h> #import <arpa/inet.h> @interface ViewController () { } @end @implementation ViewController CFWriteStreamRef oStream; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.view.backgroundColor = [UIColor groupTableViewBackgroundColor]; [self initSocket]; } -(void)initSocket{ @autoreleasepool { //建立Socket,指定TCPServerAcceptCallBack //做为kCFFSocketAcceptCallBack事件的监听函数 CFSocketRef _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET,/*指定协议族,若是参数为0或者负数,则默认为PF_INET*/ SOCK_STREAM,/*指定Socket类型,若是协议族为PF_INET,且该参数为0或者负数,则它会默认为SOCK_STREAM,若是要使用UDP协议,则该参数指定为SOCK_DGRAM*/ IPPROTO_TCP ,/*指定通信协议。若是前一个参数为SOCK_STREAM,则默认为使用TCP协议,若是前一个参数为SOCK_DGRAM,则默认使用UDP协议*/ kCFSocketAcceptCallBack,/*指定下一个函数所监听的事件类型*/ TCPServerAcceptCallBack, NULL); if (_socket == NULL) { NSLog(@"建立Socket失败!"); return; } int optval = 1; //设置容许重用本地地址和端口 setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(optval)); //定义sockaddr_in类型的变量,该变量将做为CFSocket的地址 struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_len = sizeof(addr4); addr4.sin_family = AF_INET; //设置该服务器监听本机任意可用的IP地址 // addr4.sin_addr.s_addr = htonl(INADDR_ANY); //设置服务器监听地址 addr4.sin_addr.s_addr = inet_addr("192.168.199.171"); //设置服务器监听端口 addr4.sin_port = htons(30000); //将IPv4的地址转换为CFDataRef CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4)); //将CFSocket绑定到指定IP地址 if (CFSocketSetAddress(_socket, address) != kCFSocketSuccess) { NSLog(@"地址绑定失败!"); //若是_socket不为NULL,则释放_socket if (_socket) { CFRelease(_socket); exit(1); } _socket = NULL; } NSLog(@"----启动循环监听客户端链接---"); //获取当前线程的CFRunLoop CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent(); //将_socket包装成CFRunLoopSource CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0); //为CFRunLoop对象添加source CFRunLoopAddSource(cfRunLoop, source, kCFRunLoopCommonModes); CFRelease(source); //运行当前线程的CFRunLoop CFRunLoopRun(); } } void readStream(CFReadStreamRef iStream, CFStreamEventType evenType, void *clientCallBackInfo) { UInt8 buff[2048]; CFIndex hasRead = CFReadStreamRead(iStream, buff, 2048); if (hasRead > 0) { //强制只处理hasRead前面的数据 buff[hasRead] = '\0'; printf("接收到数据:%s\n",buff); const char *str = "OK!你收到了Mac服务器的消息!\n"; //向客户端输出数据 CFWriteStreamWrite(oStream, (UInt8 *)str, strlen(str) + 1); } } //有客户端链接进来的回调函数 void TCPServerAcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { //若是有客户端Socket链接进来 if (kCFSocketAcceptCallBack == type) { //获取本地Socket的Handle 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 ) { NSLog(@"error"); exit(1); } //获取链接信息 struct sockaddr_in *addr_in = (struct sockaddr_in *)name; NSLog(@"%s:%d链接进来了",inet_ntoa(addr_in->sin_addr),addr_in->sin_port); CFReadStreamRef iStream; //建立一组可读/写的CFStream CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &iStream, &oStream); if (iStream && oStream) { //打开输入流和输出流 CFReadStreamOpen(iStream); CFWriteStreamOpen(oStream); CFStreamClientContext streamContext = {0,NULL,NULL,NULL}; if (!CFReadStreamSetClient(iStream, kCFStreamEventHasBytesAvailable, readStream,/*回调函数,当有可读的数据时调用*/ &streamContext)) { exit(1); } CFReadStreamScheduleWithRunLoop(iStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); const char *str = "OK!你收到了Mac服务器的消息!\n"; //向客户端输出数据 CFWriteStreamWrite(oStream, (UInt8 *)str, strlen(str) + 1); } } } @end
@interface ViewController ()<UIAlertViewDelegate> { CFSocketRef _socket; NSString *myName; BOOL isOnline; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.view.backgroundColor = [UIColor groupTableViewBackgroundColor]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"名字" message:@"请输入您的名字" delegate:self cancelButtonTitle:@"肯定" otherButtonTitles: nil]; alert.alertViewStyle = UIAlertViewStylePlainTextInput; [alert show]; } ///////////////////监听来自服务器的信息/////////////////// -(void)ReadStream { char buffer[255]; int hasRead; //与本机关联的Socket若是已经失败,则返回-1:INVALID_SOCKET while ((hasRead = recv(CFSocketGetNative(_socket), buffer, sizeof(buffer), 0))) { NSString *content = [[NSString alloc] initWithBytes:buffer length:hasRead encoding:NSUTF8StringEncoding]; dispatch_async(dispatch_get_main_queue(), ^{ self.showView.text = [NSString stringWithFormat:@"%@\n%@",content,self.showView.text]; }); } } - (IBAction)send:(id)sender { if (isOnline) { NSString *stringTosend = [NSString stringWithFormat:@"%@说:%@",myName,self.inputField.text]; self.inputField.text = nil; const char* data = [stringTosend UTF8String]; send(CFSocketGetNative(_socket), data, strlen(data) + 1, 1); } else{ NSLog(@"暂未链接服务器"); } } - (IBAction)finishEdit:(id)sender { [sender resignFirstResponder]; } - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { myName = [alertView textFieldAtIndex:0].text; //建立Socket,无须回调函数 _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketNoCallBack, nil, NULL); if (_socket != nil) { struct sockaddr_in addr4; memset(&addr4, 0, sizeof(addr4)); addr4.sin_len = sizeof(addr4); addr4.sin_family = AF_INET; //设置远程服务器的IP地址 // addr4.sin_addr.s_addr = htonl(INADDR_ANY); //设置远程服务器监听地址 addr4.sin_addr.s_addr = inet_addr("192.168.199.171"); //设置远程服务器监听端口 addr4.sin_port = htons(30000); //将IPv4的地址转换为CFDataRef CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4)); CFSocketError result = CFSocketConnectToAddress(_socket, address, 5); //将CFSocket绑定到指定IP地址 if (result == kCFSocketSuccess) { isOnline = YES; //启用新线程来读取服务器响应的数据 [NSThread detachNewThreadSelector:@selector(ReadStream) toTarget:self withObject:nil]; } } } @end
通信效果:服务器
服务端如图:socket
客户端如图:async