Должен ли [nsInputStream read:...] возвращаться, если [nsInputStream close] вызывается другим потоком?

Мне кажется, что любой объект NSInputStream должен выскочить из метода read:, если поток закрыт другим потоком независимо от другого конца соединения с сокетом. Но в некоторых случаях это не похоже на правду. Похоже, что если другая сторона сначала не отправит что-либо хотя бы один раз перед соединением, метод read: не будет реагировать на закрытие потока.

Код для открытия соединения:

    // Open the socket...
    CFStreamCreatePairWithSocketToHost(NULL, Host, Port, &readStream, &writeStream);

    // Create NSStream objects for our use...
    inputStream = (NSInputStream *)readStream;
    outputStream = (NSOutputStream *)writeStream;

    // take ownership of the NSStream objects...
    [inputStream retain];
    [outputStream retain];

    // open the streams....
    [inputStream open];
    [outputStream open];

Код для закрытия соединения:

    // Close the streams...
    [inputStream close];
    [outputStream close];

    // Release ownership...
    [outputStream release];
    [inputStream release];

    // clear reference values...
    outputStream = nil;
    inputStream = nil;

В теме получения:

-(uint8_t) GetByte
{
    uint8_t c;
    int N = [inputStream read:&c maxLength:1];
    if ( N < 1 )
        @throw [[TcpClientException alloc] init];
    return c;
}

Когда я иду, чтобы закрыть поток из основного потока, поток получения остается в методе чтения. В конце концов это время ожидания и вылетает. Даже сбой не приводит к выбрасыванию какого-либо объекта (я пытался окружить код, чтобы поймать что-нибудь (id) и ничего не получил).

Как надежно заставить чтение появляться каждый раз, когда потоки должны быть закрыты?

Дополнительно:

Я использую XCODE 4.4.1 на ML с симулятором iPad 5.1.

Если я только закрываю inputStream и не освобождаю или устанавливаю ноль, то проблема также возникает.

1 ответ

Решение

После долгих исследований я столкнулся с другим потоком здесь, в SO, который намекал на ответ, что, поскольку локальное устройство отключается, не будет никакого события от соединения (из удаленной конечной точки), которое передается через метод чтения. Идея заключалась в том, что, поскольку локальное устройство отвечает за отключение, оно будет знать, что оно не должно входить в метод чтения (что не будет ничего для чтения). Это немного неожиданно, поскольку пользователь может отключиться, когда поток получателя уже находится в методе чтения. НО... iOS была разработана, очевидно, не для того, чтобы полагаться на потоки получателя, а на события в цикле выполнения (что является еще одной проблемой, но я не хочу вдаваться в подробности здесь). В частности, учитывая событие из цикла выполнения, в котором говорится, что данные доступны, вы вводите метод read. Таким образом, вы никогда не входите в чтение и зависаете в ожидании первого байта. Это очень отличается от программирования сокетов, которое я делал на платформе Windows в прошлом. Но все эксперименты, которые я провел до сих пор, показывают, что это проблема. У меня есть решение, которое работает сейчас, которое опирается на события из потока, которые выходят из цикла выполнения в рабочем потоке, так что сетевой трафик не мешает потоку GUI(основной).

Другие вопросы по тегам