WebRequest在并发请求/读取异步时失败

时间:2014-02-20 08:41:45

标签: c# multithreading asynchronous

给出以下设置:

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设置了ReadWriteTimeoutWebRequest(请参阅上面的GetResponseAsync扩展方法)。

非常感谢任何建议/提示。

0 个答案:

没有答案