Должен ли [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 и не выпускаю или не устанавливаю значение nil, проблема также возникает.


person user574771    schedule 29.08.2012    source источник


Ответы (1)


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

person user574771    schedule 07.09.2012
comment
Означает ли это, что вы когда-либо читали только 1 байт за раз, как только сообщается о HasBytesAvailable? - person xaphod; 26.02.2015