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

本文关键字:NetworkStream EndRead BeginRead 超时 实现 使用 | 更新日期: 2023-09-27 18:10:48

我写了下面的函数来实现一个超时功能使用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紧凑框架3.5,它不支持NetworkStream.ReadTimeoutNetworkStream.WriteTimeout属性。

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

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

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

除了你代码中的内存屏障问题(正如Hans也指出的),如果我是你,我会使用响应式扩展,而不是使这段代码只需要三行代码。如果您有时间,我强烈建议您使用Rx。

欢呼