簡體   English   中英

該操作已超時使用WebClient.DownloadFile並更正了url

[英]The operation has timed out with WebClient.DownloadFile and correct url's

我是批量上傳產品到數據庫。

我將圖像網址下載到用於產品的網站。

我編寫的代碼在前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:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM