【问题标题】:The operation has timed out with WebClient.DownloadFile and correct url'sWebClient.DownloadFile 和正确的 url 操作已超时
【发布时间】:2010-12-01 21:54:59
【问题描述】:

我正在将产品批量上传到数据库。

我正在下载要用于产品的网站的图片网址。

我编写的代码在前 25 次迭代中运行良好(由于某种原因总是这个数字),但随后抛出 System.Net.WebException “操作已超时”。

if (!File.Exists(localFilename))
{
    using (WebClient Client = new WebClient())
    {
        Client.DownloadFile(remoteFilename, localFilename);
    }
}

我检查了它请求的远程 url,它是一个返回图像的有效图像 url。

另外,当我使用调试器单步执行时,我没有收到超时错误。

帮助! ;)

【问题讨论】:

  • 似乎当我遍历调试器时,我没有收到超时错误。有什么原因吗?

标签: c# .net webclient download


【解决方案1】:

我有同样的问题,我解决了它添加这行到配置文件 app.config:

<system.net>
  <connectionManagement>
    <add address="*" maxconnection="100" />
  </connectionManagement>
</system.net>

【讨论】:

    【解决方案2】:

    这是 manji 答案的略微简化版本:

        private static void DownloadFile(Uri remoteUri, string localPath)
        {
            var request = (HttpWebRequest)WebRequest.Create(remoteUri);
            request.Timeout = 30000;
            request.AllowWriteStreamBuffering = false;
    
            using (var response = (HttpWebResponse)request.GetResponse())
            using (var s = response.GetResponseStream())
            using (var fs = new FileStream(localPath, FileMode.Create))
            {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = s.Read(buffer, 0, buffer.Length)) > 0)
                {
                    fs.Write(buffer, 0, bytesRead);
                    bytesRead = s.Read(buffer, 0, buffer.Length);
                }
            }
        }
    

    【讨论】:

    【解决方案3】:

    似乎WebClient 没有关闭它在完成时使用的Response 对象,在您的情况下,这将导致同时打开许多响应,并且远程服务器上的连接限制为 25 个,你得到了“超时异常”。当您调试时,早期打开的响应会由于其内部超时等原因而关闭...... (我用反射器检查了WebClient,我找不到关闭响应的指令)。

    我建议您使用HttpWebRequest &amp; HttpWebResponse,以便在每次下载后清理对象:

    HttpWebRequest request;
    HttpWebResponse response = null;
    
    try
    {
    
       FileStream fs;
       Stream s;
       byte[] read;
       int count;
    
       read = new byte[256];
    
       request = (HttpWebRequest)WebRequest.Create(remoteFilename);
       request.Timeout = 30000;
       request.AllowWriteStreamBuffering = false;
    
       response = (HttpWebResponse)request.GetResponse();
       s = response.GetResponseStream();  
    
       fs = new FileStream(localFilename, FileMode.Create);   
       while((count = s.Read(read, 0, read.Length))> 0)
       {
          fs.Write(read, 0, count);
          count = s.Read(read, 0, read.Length);
       }
    
       fs.Close();
       s.Close();
    }
    catch (System.Net.WebException)
    {
        //....
    }finally
    {
       //Close Response
       if (response != null)
          response.Close();
    }
    

    【讨论】:

      【解决方案4】:

      如果我站在你的立场上,我会调查以下几种可能性:

      • 如果您从多个线程运行此代码,您可能会遇到 System.Net.ServicePointManager.DefaultConnectionLimit 属性。启动应用程序时尝试将其增加到 50-100。请注意,我认为这不是您的问题,但尝试这比下面的其他内容更容易。 :-)
      • 另一种可能性是您淹没了服务器。这对于单线程客户端通常很难做到,但由于多个其他客户端也可能正在访问服务器,所以这是可能的。但是因为问题总是发生在#25,这似乎不太可能,因为您希望看到更多的变化。
      • 您可能遇到了客户端和服务器之间的 keepalive HTTP 连接备份问题。这似乎也不太可能。
      • 25 的硬截止让我认为这可能是代理或防火墙限制,无论是在您端还是在服务器端,从一个客户端 IP 到一台服务器(或代理)的 >25 个连接将受到限制。

      我的钱花在后一个上,因为它总是在大量请求时中断,并且单步执行调试器(也就是更慢!)不会引发问题。

      为了测试这一切,我会从简单的事情开始:在每次 HTTP 调用之前坚持一个延迟 (Thread.Sleep),看看问题是否消失。如果是这样,请减少延迟,直到问题再次出现。如果没有,将延迟增加到一个很大的数字(例如 10 秒),直到问题消失。如果它没有在 10 秒延迟后消失,那真是一个谜,我需要更多信息来诊断。

      如果它确实会延迟消失,那么您需要找出原因 - 以及该限制是否是永久性的(例如,您无法更改的服务器防火墙)或您可以更改的内容。要获取更多信息,您需要对请求进行计时(例如,在每次通话之前和之后检查 DateTime.Now),看看您是否看到了某种模式。如果时间都是一致的并且突然变得很大,这表明网络/防火墙/代理限制。如果时间逐渐增加,则表明您正在逐渐超载并延长其请求队列的服务器。

      除了对请求进行计时,我还将您的网络客户端调用的超时设置为更长,这样您就可以确定超时是无限的还是比默认值长一点。为此,您需要 WebClient 类的替代方案,因为它不支持超时。 MSDN 论坛上的This thread 有一个合理的替代代码示例。

      在代码中添加计时的另一种方法是使用 Fiddler:

      • 下载fiddler并启动它。
      • 将您的 webclient 代码的 Proxy 属性设置为指向 fiddler 代理 (localhost:8888)
      • 运行您的应用程序并查看 fiddler。

      【讨论】:

      • 同意,这听起来绝对像是一个连接限制问题。这也可以解释为什么在调试器中单步执行会“修复”它,因为当开发人员坐在调试器中时,一些连接会被释放。
      • 我还建议使用“CurrPorts”实用程序 (nirsoft.net/utils/cports.html),它会在漂亮的 GUI 中显示当前打开的连接(或者您可以使用 Windows 内置的“netstat”命令)。跨度>
      • 增加System.Net.ServicePointManager.DefaultConnectionLimit 对我有用(我在线程中使用DownloadFile)。 default value 是 2。
      猜你喜欢
      • 1970-01-01
      • 2012-09-21
      • 2011-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多