8

製品をデータベースにバッチアップロードしています。

商品に使用するサイトの画像URLをダウンロードしています。

私が書いたコードは、最初の 25 回の反復 (何らかの理由で常にその数) では正常に動作しますが、その後 System.Net.WebException "The operation has timed out" がスローされます。

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

リクエストしているリモート URL を確認しましたが、画像を返す有効な画像 URL です。

また、デバッガーでステップ実行すると、タイムアウト エラーが発生しません。

ヘルプ!;)

4

4 に答える 4

20

私があなたの立場だったとしたら、いくつかの可能性を調査します。

  • このコードを複数のスレッドから実行している場合は、System.Net.ServicePointManager.DefaultConnectionLimit プロパティに衝突している可能性があります。アプリの起動時に 50 ~ 100 に増やしてみてください。これはあなたの問題ではないと思いますが、これを試すのは以下の他のものよりも簡単です. :-)
  • 別の可能性は、サーバーを圧倒していることです。これは通常、シングルスレッドのクライアントでは困難ですが、他の複数のクライアントもサーバーにアクセスしている可能性があるため可能です。しかし、問題は常に #25 で発生するため、より多くの変動が見られると予想されるため、これはありそうにありません。
  • クライアントとサーバー間のキープアライブ HTTP 接続で問題が発生している可能性があります。これもありそうにない。
  • 25 のハード カットオフは、これが、1 つのクライアント IP から 1 つのサーバー (またはプロキシ) への 25 を超える接続が調整される、エンドまたはサーバーのプロキシまたはファイアウォールの制限である可能性があると考えさせます。

私のお金は後者のものにあります。なぜなら、それは常に良いラウンド数のリクエストで壊れ、デバッガーをステップインしても問題が引き起こされないからです。

これらすべてをテストするには、簡単なことから始めます。各 HTTP 呼び出しの前に遅延 (Thread.Sleep) を挿入し、問題が解決するかどうかを確認します。その場合は、問題が再発するまで遅延を減らします。そうでない場合は、問題が解決するまで遅延を大きくしてください (例: 10 秒)。10 秒の遅延で消えない場合、それは本当に謎であり、診断するにはさらに情報が必要です.

遅れて解消される場合は、その理由と、制限が永続的なもの (変更できないサーバーのファイアウォールなど) なのか、変更できるものなのかを突き止める必要があります。詳細情報を取得するには、リクエストの時間を計って (たとえば、各呼び出しの前後に DateTime.Now をチェックして)、パターンが見られるかどうかを確認します。タイミングがすべて一貫しており、突然大きくなる場合は、ネットワーク/ファイアウォール/プロキシのスロットリングを示唆しています。タイミングが徐々に増加する場合は、サーバーが徐々に過負荷になり、リクエスト キューが長くなっていることを示しています。

リクエストのタイミングに加えて、webclient 呼び出しのタイムアウトをより長く設定して、タイムアウトが無限か、デフォルトより少しだけ長いかを判断できるようにします。これを行うには、タイムアウトをサポートしていないため、WebClient クラスの代替が必要になります。MSDN フォーラムのこのスレッドには、合理的な代替コード サンプルがあります。

コードにタイミングを追加する代わりに、Fiddler を使用できます。

  • fiddlerをダウンロードして起動します。
  • webclient コードの Proxy プロパティを設定して、フィドラー プロキシ (localhost:8888) を指すようにします。
  • アプリを実行して、フィドラーを見てください。
于 2009-10-01T21:00:32.503 に答える
4

マンジの答えを少し簡略化したものを次に示します。

    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);
            }
        }
    }
于 2013-03-12T20:50:24.577 に答える
3

私は同じ問題を抱えており、次の行を構成ファイル app.config に追加して解決します。

<system.net>
  <connectionManagement>
    <add address="*" maxconnection="100" />
  </connectionManagement>
</system.net>
于 2015-12-16T14:38:16.907 に答える