Как открыть несколько потоков сокетов на одном цикле выполнения в iOS, возможно? - PullRequest
1 голос
/ 03 октября 2011

В моей программе у меня запланирован поток чтения и записи в runloop, и он работает нормально.Позже в программе я хочу открыть другой поток для чтения или записи, в зависимости от роли, затем я хочу запланировать его на тот же цикл выполнения на том же сервере, но это не работает.Я вызвал open для вновь созданного потока, но не вижу ни одного события NSStreamEventOpenCompleted, поступающего во вновь открытый поток.Вот как я создаю потоки и реализацию делегата для обработки событий:

controller.m

- (void)initNetworkCommunication:(NSString *)ip_address withPort:(NSInteger)port role:(network_role_t)role
{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;

    NSLog(@"server IP: %@, port: %d, role: %d", ip_address, port, role);
    if (port != 8080) {
        if (role == HOST) {
            CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)ip_address, port, NULL, &writeStream);
            imageOutStream = (NSOutputStream *)writeStream;
            [imageOutStream setDelegate:self];
            [imageOutStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [imageOutStream open];
            NSLog(@"host connected");
        } else if (role == CLIENT) {
            CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)ip_address, port, &readStream, NULL);
            imageInStream = (NSInputStream *)readStream;
            [imageInStream setDelegate:self];
            [imageInStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [imageInStream open];
            NSLog(@"client connected");
        }
    } else {
        CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)ip_address, port, &readStream, &writeStream);
        inputStream = (NSInputStream *)readStream;
        outputStream = (NSOutputStream *)writeStream;
        [inputStream setDelegate:self];
        [outputStream setDelegate:self];
        [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        [inputStream open];
        [outputStream open];
    }
}

реализация делегата:

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 
{

    switch (streamEvent) {
        case NSStreamEventHasBytesAvailable:
            if (theStream == inputStream) {
                /* send regular data */
            } else if (theStream == imageInStream) {
                /* send raw data */
            }
        break;
        case NSStreamEventOpenCompleted:
            if (theStream == imageOutStream) {
                NSLog(@"imageOutStream opened");
            } else if (theStream == imageInStream) {
                NSLog(@"imageInStream opened");
            }
        break;
        case NSStreamEventErrorOccurred:
            //NSError *theError = [theStream streamError];
            NSLog(@"Socket error string: %@", [[theStream streamError] localizedDescription]);
        break;
    }
}

Так что я надеваюне видно, что imageOutStream открылся и imageInStream открылся распечатан, когда они подключены к серверу.Что я обнаружил, так это в scheduleInRunLoop: для imageInStream и imageOutStream, если я использую mainRunLoop вместо currentRunLoop, я вижу распечатанный открытый поток, но даже при том, что отправка и получение все еще вызывают проблемы.Я делаю что-то не так при планировании потоков?Или я должен использовать другой метод, кроме scheduleInRunLoop, если я хочу создать несколько потоков сокетов.Спасибо за помощь.

1 Ответ

0 голосов
/ 04 октября 2011

Во-первых, я бы добавил безусловное ведение журнала в начало -stream: handleEvent: как NSLog(@"stream %@ got event %x", theStream, (unsigned)streamEvent);. Это скажет вам, если вы получаете события, которые вы не обрабатываете, как я подозреваю, вы (вроде).

В документах NSStream ,

Константы событий потока

Одна или несколько из этих констант могут быть отправлены делегату в виде битового поля во втором параметре потока: handleEvent:.

Если это битовое поле, вы не можете его легко включить. Это может быть 3 (NSStreamEventOpenCompleted|NSStreamEventHasBytesAvailable), что означает, что поток открыл и есть данные, доступные для чтения.

Простое исправление выглядит примерно так

if (streamEvent&NSStreamEventOpenCompleted) {
  ...
}

if (streamEvent&NSStreamEventHasBytesAvailable) {
  ...
}

...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...