开发者

iphone network cfsocket callback multithread

开发者 https://www.devze.com 2023-04-12 07:24 出处:网络
I am trying to write an iOS application which listens for TCP broadcasts and acts on the data. More advanced implementations seem to suggest using background threads and raw sockets to implement this

I am trying to write an iOS application which listens for TCP broadcasts and acts on the data. More advanced implementations seem to suggest using background threads and raw sockets to implement this kind of feature, but I thought as a first attempt I would use CFSocket to keep things simple.

The problem is that when I run it, it's fine , but it run in main thread,don't run in a new thread. why doesn't the callback function run in a background thread?

Here is the code:

- (void)connecToServer{
    int yes = 1;
    CFSocketContext CTX = {0,self,NULL,NULL,NULL};
    _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketDataCallBack, TCPServerConnectCallBack, &CTX);    
    setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
    struct sockaddr_in addr4;    
    memset(&addr4, 0, sizeof(addr4));    
    addr4.sin_len = sizeof(addr4);    
    addr4.sin_family = AF_INET;    
    addr4.sin_port = htons(6242);    
    addr4.sin_addr.s_addr = inet_addr("");    
    addr开发者_如何学JAVAess = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4));        
    CFRunLoopRef cfrl = CFRunLoopGetCurrent();    
    CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0);    
    CFRunLoopAddSource(cfrl, source, kCFRunLoopCommonModes);    
    CFRelease(source);
}

the callback function:

static void TCPServerConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info){
    NSData *nsdata = (NSData*)data;
    NSUInteger len = [nsdata length];
    Byte *byteData = (Byte*)malloc(len);
    memcpy(byteData, [nsdata bytes], len);
    Byte *userData;
    NetWorkConnect *netWorkConnect = (NetWorkConnect*)info;
    switch(byteData[5]){
        case 2:
            userData = (Byte*)malloc(len-9);
            memcpy(userData, byteData+7, len-9);
            memset(&(netWorkConnect->oQuota), 0, sizeof(netWorkConnect->oQuota));
            [netWorkConnect performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
           break;
        default:
           break;
    }
}


You may want to use cocoaasyncsocket: it will make your life much easier. http://code.google.com/p/cocoaasyncsocket/


kCFSocketDataCallBack is designed to be used with a run loop. Background threads, e.g. GCD, are an alternative to run loops and therefore don't use them. Hence CFRunLoopGetCurrent() will always return the main thread's run loop, regardless on which GCD queue you are.

To run sockets on background threads you need to configure the socket as a dispatch source. See Apple docs for an example for a file descriptor, but you can just exchange it with the socket descriptor that you get via CFSocketGetNative() and it will work fine.

Code example:

dispatch_queue_t _queue = dispatch_queue_create("foo", DISPATCH_QUEUE_CONCURRENT);

CFSocketRef _s_cf   = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_ICMP, 0, NULL, NULL);
int _s_bsd  = CFSocketGetNative(_s_cf);

// make non-blocking
if (fcntl(_s_bsd, F_SETFL, O_NONBLOCK) == -1) {
    // handle error
}

dispatch_source_t _readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, _s_bsd, 0, _queue);

dispatch_source_set_event_handler(_readSource, ^{
    size_t estimated = dispatch_source_get_data(self->_readSource) + 1;
    NSMutableData *data = [NSMutableData dataWithCapacity:estimated];
    if (read(self->_s_bsd, data.mutableBytes, estimated) == -1) {
        // handle error
    } else {
        // handle data
    }
});

dispatch_resume(_readSource);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号