该操作已超时使用WebClient.DownloadFile并更正了url

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

我将图片url下载到用于产品的网站。

我编写的代码在前25次迭代中工作正常(由于某种原因总是那个数字),但随后抛出一个System.Net.WebException“操作已经超时”。

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

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

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

救命! ;)

如果我在你的鞋子里,这里有一些我调查的可能性:

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

我的钱是在后者,因为它总是在一个很好的轮数请求中断,并且踩到调试器(又名更慢!)不会触发问题。

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

如果它确实延迟了,那么你需要找出原因 – 以及限制是否是永久性的(例如服务器的防火墙,你无法改变)或者你可以改变的东西。 要获得更多信息,您需要为请求计时(例如,在每次调用之前和之后检查DateTime.Now)以查看是否看到模式。 如果时间一致并且突然变得庞大,则表明网络/防火墙/代理限制。 如果时间逐渐增加,则表明服务器正在逐渐超载并延长其请求队列。

除了对请求进行计时之外,我还会将webclient调用的超时设置为更长,这样您就可以确定超时是无限还是比默认值更长。 为此,您需要WebClient类的替代方法,因为它不支持超时。 MSDN论坛上的这个主题有一个合理的替代代码示例。

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

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

似乎WebClient没有关闭它在完成时使用的Response对象,这会导致在你的情况下同时打开许多响应并且远程服务器上有25个连接的限制,你得到了’Timeout exception’ 。 当你调试时,早期打开的响应由于它们的内部超时等而被关闭……(我认为使用Reflector的WebClient ,我找不到关闭响应的指令)。

我建议你使用HttpWebRequest & 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(); } 

这是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); } } } 

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