1

在我看来,如果流被另一个线程关闭,无论套接字连接的另一端如何,任何 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)并且什么也没有得到)。

每次要关闭流时,如何可靠地强制读取弹出?

此外:

我在 ML 上使用 XCODE 4.4.1 和 5.1 iPad 模拟器。

如果我只关闭 inputStream 而没有释放或设置为 nil,那么也会出现问题。

4

1 回答 1

0

经过大量调查后,我在 SO 遇到了另一个线程,它暗示了答案,由于本地设备正在断开连接,因此通过 read 方法传递的连接(来自远程端点)不会发生任何事件。这个想法是,由于本地设备负责断开连接,它会知道它不应该进入读取方法(不会有任何东西要读取)。这有点出乎意料,因为当接收器线程已经在读取方法中时,用户可能会断开连接。但是... iOS 的设计显然不依赖于接收器线程,而是运行循环中的事件(这是另一个问题,但我不想在这里讨论)。具体来说,给定来自运行循环的事件表明有可用数据,您输入 read 方法。因此,您永远不会进入读取并挂起等待第一个字节。这与我过去在 Windows 平台上完成的套接字编程非常不同。但到目前为止我所做的所有实验都表明这是问题所在。我有一个现在可以工作的解决方案,它依赖于来自工作线程中运行循环的流中的事件,这样网络流量就不会干扰 GUI(主)线程。

于 2012-09-07T21:05:22.980 回答