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

11 篇文章 0 订阅

建立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发送出去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值