使用NetworkStream.BeginRead和NetworkStream.EndRead实现超时

时间:2011-10-08 12:39:55

标签: c# .net asynchronous networkstream

我编写了以下函数来使用NetworkStream的异步读取函数(BeginReadEndRead)来实现超时功能。它一直正常,直到我注释掉Trace.WriteLine("bytesRead: " + bytesRead);行。为什么呢?

private int SynchronousRead(byte[] buffer, int count)
{
    int bytesRead = 0;
    bool success = false;
    IAsyncResult result = null;

    result = _stream.BeginRead(
        buffer, 0, count,
        delegate(IAsyncResult r)
        {
            bytesRead = _stream.EndRead(r);
        },
        null);

    success = result.AsyncWaitHandle.WaitOne(_ioTmeoutInMilliseconds, false);

    if (!success)
    {
        throw new TimeoutException("Could not read in the specfied timeout.");
    }

    //If I remove this line, bytesRead is always 0
    Trace.WriteLine("bytesRead: " + bytesRead);

    return bytesRead;
}

万一你想知道,我必须这样做,因为我最终需要定位.Net Compact Framework 3.5,它不支持NetworkStream.ReadTimeoutNetworkStream.WriteTimeout属性。< / p>

2 个答案:

答案 0 :(得分:5)

一个有趣的线程错误。在发出等待句柄信号后,分配bytesRead变量。有两件事可能会出错:方法在分配之前返回。或者线程读取过时的值,因为它们在WaitOne()调用之后没有内存障碍。 Trace语句修复了这个问题,因为它将主线程延迟了足够长的时间以允许写入变量。它有一个内部锁,可确保缓存一致。

您需要一个额外的AutoResetEvent来表示写入了bytesRead变量。

答案 1 :(得分:0)

除了代码中的内存屏障问题(正如汉斯还指出的那样),如果我是你,我会使用Reactive Extension代替只需三行代码的代码段。如果你有时间,我强烈建议你改用Rx。

干杯