Должен ли [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(основной).