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

发布于 2024-12-08 22:45:21 字数 950 浏览 1 评论 0原文

我编写了以下函数,以使用 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.ReadTimeout 和 NetworkStream.WriteTimeout 属性。

I've written the following function to implement a timeout feature using NetworkStream's asynchronous read functions (BeginRead and EndRead). It works fine until I comment out the line Trace.WriteLine("bytesRead: " + bytesRead);. Why?

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;
}

Just in case you're wondering, I have to do this because I will eventually need to target the .Net Compact Framework 3.5 and it doesn't support the NetworkStream.ReadTimeout and NetworkStream.WriteTimeout properties.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别忘他 2024-12-15 22:45:21

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

您将需要一个额外的 AutoResetEvent 来指示 bytesRead 变量已写入。

An interesting threading bug. The bytesRead variable is assigned after the wait handle is signaled. Two things can go wrong: the method returns before the assignment is made. Or the thread reads a stale value since their is no memory barrier past the WaitOne() call. The Trace statement fixes the problem because it delays the main thread long enough to allow the variable to be written. And it has an internal lock that ensures the cache is coherent.

You'll need an additional AutoResetEvent that signals that bytesRead variable was written.

伴我心暖 2024-12-15 22:45:21

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

干杯

Besides the memory barrier problem in you code (As Hans also pointed), If i were you i'd use Reactive Extension instead that would make this code segment in just three lines of code. If you have time, I'd strongly suggest you to use Rx instead.

Cheers

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文