【发布时间】:2019-09-06 13:59:25
【问题描述】:
我尝试使用 await/async 读取 HttpWebResponse 流:
async static Task testHttpWebClientAsync()
{
string url = "http://localhost/1.txt";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)await req.GetResponseAsync();
Stream stream = resp.GetResponseStream();
stream.ReadTimeout = 10 * 1000;
byte[] buffer = new byte[1024];
while (await stream.ReadAsync(buffer, 0, buffer.Length) > 0)
{
//time out exception never thrown
}
}
但它不起作用,它永远不会在 ReadAsync 上超时。 为了比较,非异步版本与相同的本地主机测试服务器完美配合:
static void testHttpWebClient()
{
string url = "http://localhost/1.txt";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream stream = resp.GetResponseStream();
stream.ReadTimeout = 10 * 1000;
byte[] buffer = new byte[1024];
while (stream.Read(buffer, 0, buffer.Length) > 0)
{
//time out exception thrown here
}
}
以上代码在控制台应用中测试:
static void Main(string[] args)
{
testHttpWebClient();
MainAsync(args).GetAwaiter().GetResult();
}
async static Task MainAsync(string[] args)
{
await testHttpWebClientAsync();
}
但这与问题无关,确实我在一个WinForms项目中发现了问题并创建了控制台项目来测试问题。
作为参考,测试服务器代码如下:
int c = 10;
byte[] ba = new byte[1024];
SendHeader(sHttpVersion, sMimeType,(int) ba.Length*c, " 200 OK", ref mySocket);
for (int k = 0; k < c; k++)
{
//set break point here
SendToBrowser(ba, ref mySocket);
}
关于 SO 有几个类似的主题,但似乎没有一个能解决这个问题。从 API 设计的角度来看,显然没有理由 ReadAsync() 不会像 Read() 那样超时,ReadAsync 只需要同时观察套接字和内部计时器事件,这就是 Task.Delay() 的工作原理。这与 CancellationToken 等无关,因为我们不需要取消任何东西,即使 ReadAsync 也有接受 CancellationToken 的版本。
所以这个问题既是针对问题的解决方案,也是为什么 ReadAsync 不会像预期的那样超时。
【问题讨论】:
-
为什么不对实际请求设置超时时间?
req.TimeOut = 10 * 1000? -
@Çöđěxěŕ 首先,它也不起作用。其次,req.TimeOut 是关于req.GetResponse 的超时时间,不是读操作。确实,req.ReadWriteTimeout 也不起作用。
-
用
NetworkStream怎么样,你试过吗? -
以前从未听说过...让我们专注于上面的代码。
-
主要问题是因为它返回一个
Task,您正在等待这个任务没有取消令牌。您如何期望它超时/取消,并非所有流都支持超时以及我使用NetworkStream提到的原因...
标签: c# async-await stream timeout