您的位置:首页 > 移动开发 > IOS开发

iOS and OS X Network Programming Cookbook |Creating an echo server(CFSocket)

2015-06-30 23:46 573 查看
建立socket的方法与BSD socket相同(见上一篇),主要的不同在监听上,这里使用的是run loop对socket进行监听,这是CFNetwork的一个很大的优势

在通过BSD socket获取到listening descriptor后,通过CFSocketCreateWithNative()创建CFSocket,(这个步骤的逆向是CFSocketGetNative())然后将其加入run loop中

其实大家都知道BSD基本没有实用性,CFSocket还能用用

-(instancetype)initOnPort:(int)port {
struct sockaddr_in servaddr;
CFRunLoopSourceRef source;
const CFSocketContext context = {0, NULL, NULL, NULL, NULL};
self.errorCode = NOERROR;
if ((self.listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0) {
self.errorCode = SOCKETERROR;
} else {
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
if (bind(self.listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) <0) {
self.errorCode = BINDERROR;
} else {
if (listen(self.listenfd, LISTENQ) <0) {
self.errorCode = LISTENERROR;
} else {
self.sRef = CFSocketCreateWithNative(NULL, self.listenfd, kCFSocketAcceptCallBack,
acceptConnection, &context);
if (self.sRef == NULL) {
self.errorCode = CFSOCKETCREATEERROR;
}else {
source = CFSocketCreateRunLoopSource(NULL, self.sRef, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
CFRelease(source);
CFRunLoopRun();
}
}
}

}
return self;
}
依次介绍下CFSocketCreateWithNative的几个参数:

CFAllocatorRef:用来定位新对象的内存位置,一般用NULL或者kCFAllocatorDefault表示当前默认

CFSocketNativeHandle:之前创建的 native BSD socket

CFOptionFlags:关于回调的选项依次是kCFSocketNoCallBack/...ReadCallBack/...AcceptCallBack/...DataCallBack/...ConnectCallBack/...WriteCallBack

CFSocketCallBack:回调调用的函数,这是个c函数(acceptConnection方法)

CFSocketContext:并不知道有什么卵用

CFSocketCreateRunLoopSource的几个参数:

CFAllocatorRef:同上

CFSocketRef:之前通过BSD创建的那个

CFIndex:run loop中的优先级

CFRunLoopAddSource的参数:

CFRunLoopRef:所要添加进的run loop

CFRunLoopSourceRef:要加入的source

CFStringRed:run loop mode

将CFRunLoopSourceRef加入run loop后,清除掉不需要的内容

CFRelease(source);


然后运行runloop

void acceptConnection(CFSocketRef sRef, CFSocketCallBackType
cType, CFDataRef address, const void *data, void *info)
{
CFSocketNativeHandle csock = *(CFSocketNativeHandle *)data;
CFSocketRef sn;
CFRunLoopSourceRef source;
const CFSocketContext context = {0, NULL, NULL, NULL, NULL};
sn = CFSocketCreateWithNative(NULL, csock,
kCFSocketDataCallBack, receiveData, &context);
source = CFSocketCreateRunLoopSource(NULL, sn, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source,
kCFRunLoopDefaultMode);
CFRelease(source);
CFRelease(sn);
}


这里创建了一个新的CFSocketRef然后再加入另一个回调方法

void receiveData(CFSocketRef sRef, CFSocketCallBackType
cType,CFDataRef address, const void *data, void *info)
{
CFDataRef df = (CFDataRef) data;
long len = CFDataGetLength(df);
if(len <= 0) return;
UInt8 buf[len];
CFRange range = CFRangeMake(0,len);
CFDataGetBytes(df, range, buf);
buf[len]='\0';
NSString *str = [[NSString alloc] initWithData:(NSData*)data
encoding:NSASCIIStringEncoding];
NSLog(@"Received:  %@",str);
[[NSNotificationCenter defaultCenter]
postNotificationName:@"posttext" object:str];
CFSocketSendData(sRef, address, df, 0);  // Echo back
}


将data先转成CFDataRef再转成UInt8再转成NSString

最后CFSocketSendData将CFDataRef格式的data发送出去
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  socket Network iOS