在流读取上实现超时属性



我从我从中读取数据的HttpWebResponse.GetResponseStream()获取流。现在我想实现一个Timeout属性。最简单的方法是stream.ReadTimeout = timeout,但这会引发InvalidOperationException -> Timeouts are not supported on this stream

鉴于此,我正在尝试自己实现超时属性,但卡在了处置上。这是我到目前为止得到的:

public class MyStream : Stream {
    private readonly Stream _src;
    public override int ReadTimeout { get; set; }
    public MyStream (Stream src, int timeout) {
       ReadTimeout = timeout;
       _src = src;
    }
    public override int Read(byte[] buffer, int offset, int count) {
        var timer = new AutoResetEvent(false);
        int read = 0;
        ThreadPool.QueueUserWorkItem(
            _ => {
                read = _src.Read(buffer, offset, count);
                timer.Set();
            });
        bool completed = timer.WaitOne(ReadTimeout);
        if (completed) {
            return read;
        }
        throw new TimeoutException(string.Format("waited {0} miliseconds", ReadTimeout));
    }

此代码的问题是在某处正确处理TimeoutException之后。它抛出一个异常_src.Read(buffer, offset, count)说_src流已处置。

有没有办法取消 ThreadPool 方法,或者我应该使用更好的方法,哪一种方法?

谢谢

编辑

正如@JotaBe所问的,是我从HttpWebResponse获取流的代码:

_httpRequest = WebRequest.CreateHttp(url);
_httpRequest.AllowReadStreamBuffering = false;
_httpRequest.BeginGetResponse(
    result =>
        {
            try {
                _httpResponse = (HttpWebResponse)_httpRequest.EndGetResponse(result);
                stream = _httpResponse.GetResponseStream();
            }
            catch (WebException) {
                downloadCompleted.Set();
                Abort();
            }
            finally {
                downloadCompleted.Set();
            }
        },
        null);
    bool completed = downloadCompleted.WaitOne(15 * 1000);
    if (completed) {
        return new MyStream(stream, 10000);
    }

如果您试图在未从 Web 服务器接收和应答的情况下超时,那么您尝试在错误的地方执行此操作。

要获得响应,您通常会提出请求:

HttpWebResponse response = (HttpWebResponse)request.GetResponse ();

这是可以超时的操作。您必须使用开始/结束异步模式以不同的方式调用它。

有一个完整的例子在MSDN doc for HttpWebRequest.BeginGetResponse Method

此示例使用回调函数。但是,有许多不同的方法可以使用开始/结束。例如,您可以使用 IAsyncResult 中可用的 WaitHandle,如下所示:

IAsyncResult ar = req.BeginGetResponse(yourCallback, null);
bool completed = ar.AsyncWaitHandle.WaitOne(15000 /*your timeout in miliseconds*/);

这将等待 15 秒。如果响应在此之前到达,则完成将为 true。否则,完成将为假。然后,可以使用 HttpWebRequest.Abort() 方法中止请求。

开始/结束模式负责管理必要的线程。

我最终使用了 Nomad101 建议,并用尝试/捕获包围了阅读。

相关内容

  • 没有找到相关文章

最新更新