HttpClient文件下载错误 - 无法从传输连接读取数据

时间:2014-08-04 13:27:29

标签: c# httpclient

我已经编写了一个应用程序,部分可以从特定的Web服务下载文件。该代码使用HttpClient进行调用。问题是我偶尔会收到一条失败的请求,并带有以下异常消息:

无法从传输连接读取数据:连接已关闭。

我确实遇到过这些博客帖子,其中作者必须将协议版本恢复为1.0,禁用保持活动状态,并限制服务点连接的数量:

我遵循了这些指示,因为我知道如何并仍然得到错误。我还确保保留一个HttpClient实例(遵循Singleton原则)。

有趣的是,在运行Fiddler时我还没有得到错误,这让我觉得有一些事情可以在客户端完成,因为Fiddler似乎在做一些事情以保持连接活着(虽然这个问题太零散了,但这可能是一个红鲱鱼)。

还有几点说明:

  • 错误总是发生在下载过程中(从未发起请求时)。

  • 文件继续下载到失败点(首先没有延长的暂停或延迟)。

- UPDATE -

错误发生在以下行:

responseTask.Wait(cancellationTokenSource.Token);

以下是完整的例外情况:

System.AggregateException occurred   HResult=-2146233088   Message=One
or more errors occurred.   Source=mscorlib   StackTrace:
       at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
       at Form1.StartDownload() in c:\Projects\Visual Studio 2012\Demo\Demo\Form1.cs:line 88   InnerException:
System.Net.Http.HttpRequestException
       HResult=-2146233088
       Message=Error while copying content to a stream.
       InnerException: System.IO.IOException
            HResult=-2146232800
            Message=Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
            Source=System
            StackTrace:
                 at System.Net.ConnectStream.EndRead(IAsyncResult asyncResult)
                 at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.EndRead(IAsyncResult
asyncResult)
                 at System.Net.Http.Handlers.ProgressStream.EndRead(IAsyncResult
asyncResult)
                 at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)
            InnerException: System.Net.Sockets.SocketException
                 HResult=-2147467259
                 Message=An existing connection was forcibly closed by the remote host
                 Source=System
                 ErrorCode=10054
                 NativeErrorCode=10054
                 StackTrace:
                      at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
                 InnerException:

- 更新#2 -

我想我会尝试更改内容阅读中的完成选项'阅读标题'虽然在不同的位置(TODO评论的位置,读取内容流),但同样的例外情况也失败了。

- 更新#3 -

我可以确认Web服务(在IIS中托管)正在中止连接(IIS日志显示win32状态代码为1236 - ERROR_CONNECTION_ABORTED)。为了尝试缩小范围,MinFileBytesPerSec配置数据库属性设置为零(在客户端暂时停止下拉数据的情况下),连接仍然被中止。我已经仔细检查了所有超时和缓冲区大小,我认为无济于事。此刻抓住空气稀薄。任何想法都将不胜感激。

客户端设置:

private void SetupClient()
{
    // In case we're taxing the web server, limit the number
    // connections we're allowed to make to one.
    ServicePointManager.DefaultConnectionLimit = 1;

    // Set up the progress handler so that we can keep track of the download progress.
    _progressHandler = new ProgressMessageHandler();
    _progressHandler.HttpReceiveProgress += ProgressHandler_HttpReceiveProgress;

    // Create our HttpClient.
    _client = HttpClientFactory.Create(_progressHandler);
    _client.BaseAddress = new Uri("http://localhost");
    _client.Timeout = TimeSpan.FromMinutes(30);
    _client.DefaultRequestHeaders.TransferEncodingChunked = true;
}

下载逻辑:

private void StartDownload()
{
    // Create the request.
    using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Download"))
    {
        // Revert the protocol version and turn off keep alive in accordance with:
        // http://briancaos.wordpress.com/2012/07/06/unable-to-read-data-from-the-transport-connection-the-connection-was-closed/
        // http://briancaos.wordpress.com/2012/06/15/an-existing-connection-was-forcibly-closed-by-the-remote-host/

        request.Version = new Version("1.0");
        request.Headers.Add("Keep-Alive", "false");

        // Set the cancellation token's timeout to 30 minutes.
        int timeoutInMilliseconds = 30 * 60 * 1000;

        using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeoutInMilliseconds))
        {
            // Making sure that the message isn't "complete" until everything is read in so we can cancel it at anytime.
            Task<HttpResponseMessage> responseTask = _client.SendAsync(request, HttpCompletionOption.ResponseContentRead);

            responseTask.Wait(cancellationTokenSource.Token);

            using (HttpResponseMessage response = responseTask.Result)
            {
                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception("Request failed!");
                }

                Task<Stream> streamTask = response.Content.ReadAsStreamAsync();

                using (Stream contentStream = streamTask.Result)
                {
                    // TODO: Save to disk.
                }
            }
        }
    }
}

0 个答案:

没有答案