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];
}
![Socket9]()