给出以下设置:
ServicePointManager.DefaultConnectionLimit = 24;
以下代码:
public static async Task<HttpWebResponse> GetResponseAsync(this Uri uri, bool autoRedirect)
{
var request = (HttpWebRequest)WebRequest.Create(uri);
request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36";
request.AllowAutoRedirect = autoRedirect;
request.Timeout = -1;
request.ReadWriteTimeout = -1;
var response = await request.GetResponseAsync();
return (HttpWebResponse)response;
}
public static async Task<PageInfo> GetPageAsync(Uri uri)
{
using (var response = await uri.GetResponseAsync(false))
{
using(var responseStream = response.GetResponseStream())
{
var pageInfo = new PageInfo();
using (var reader = new StreamReader(responseStream))
{
try
{
pageInfo.HTML = await reader.ReadToEndAsync();
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
return pageInfo;
}
}
}
}
此设置将在15-20个并发Web请求之后,在1.000个请求之后抛出以下异常:
无法从传输连接中读取数据:现有数据 连接被远程主机强行关闭
例外是pageInfo.HTML = await reader.ReadToEndAsync()
行。
我尝试启动fiddler,并在从流中读取时检查它抛出异常的url的状态码/标头。 - 正如预期的那样,每次都是一个新的网址 - 并且全部返回301或200.因此我可以消除它是失败的主机。
将ServicePointManager.DefaultConnectionLimit
设置为较低的值有助于某些原因。 - 所以要将行await reader.ReadToEndAsync()
更改为reader.ReadToEnd()
。
似乎某种超时启动,在读取数据之前关闭流。 - 这也可以解释为什么将DefaultConnectionLimit
设置为较低的值会产生影响。这充其量是一个狂野的猜测,即使它是真的,我也看不到如何改变那个超时。我为Timeout
设置了ReadWriteTimeout
和WebRequest
(请参阅上面的GetResponseAsync
扩展方法)。
非常感谢任何建议/提示。