многопоточный обратный вызов сети iphone cfsocket

#iphone

#iPhone

Вопрос:

Я пытаюсь написать приложение для iOS, которое прослушивает TCP-трансляции и обрабатывает данные. Более продвинутые реализации, похоже, предполагают использование фоновых потоков и необработанных сокетов для реализации такого рода функций, но я подумал, что в качестве первой попытки я бы использовал CFSocket, чтобы упростить задачу.

Проблема в том, что когда я запускаю его, все в порядке, но он запускается в основном потоке, не запускается в новом потоке. почему функция обратного вызова не выполняется в фоновом потоке?

Вот код:

 - (void)connecToServer{
    int yes = 1;
    CFSocketContext CTX = {0,self,NULL,NULL,NULL};
    _socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketDataCallBack, TCPServerConnectCallBack, amp;CTX);    
    setsockopt(CFSocketGetNative(_socket), SOL_SOCKET, SO_REUSEADDR, (void *)amp;yes, sizeof(yes));
    struct sockaddr_in addr4;    
    memset(amp;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("");    
    address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)amp;addr4, sizeof(addr4));        
    CFRunLoopRef cfrl = CFRunLoopGetCurrent();    
    CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _socket, 0);    
    CFRunLoopAddSource(cfrl, source, kCFRunLoopCommonModes);    
    CFRelease(source);
}
  

функция обратного вызова:

 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(amp;(netWorkConnect->oQuota), 0, sizeof(netWorkConnect->oQuota));
            [netWorkConnect performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
           break;
        default:
           break;
    }
}
  

Комментарии:

1. Я думаю, что строка CFRunLoopRef cfrl = CFRunLoopGetCurrent(); имеет к этому какое-то отношение…

Ответ №1:

Возможно, вы захотите использовать cocoaasyncsocket: это значительно упростит вашу жизнь. http://code.google.com/p/cocoaasyncsocket /

Ответ №2:

kCFSocketDataCallBack предназначен для использования с циклом выполнения. Фоновые потоки, например, GCD, являются альтернативой циклам выполнения и поэтому не используют их. Следовательно CFRunLoopGetCurrent() , всегда будет возвращать цикл выполнения основного потока, независимо от того, в какой очереди GCD вы находитесь.

Для запуска сокетов в фоновых потоках вам необходимо настроить сокет в качестве источника отправки. Пример файлового дескриптора см. В документах Apple, но вы можете просто обменять его на дескриптор сокета, который вы получаете через CFSocketGetNative() , и он будет работать нормально.

Пример кода:

 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);