我从我从中读取数据的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 建议,并用尝试/捕获包围了阅读。