7


2

データベースに商品を一括アップロードしています。

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

私が書いたコードは最初の25回の繰り返しではうまく動作しますが(何らかの理由で常にその数になります)、System.Net.WebException "操作がタイムアウトしました"をスローします。

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

要求していたリモートURLを確認しましたが、画像を返すのは有効な画像URLです。

また、デバッガで実行してもタイムアウトエラーが発生しません。

助けて! ;)

4 Answer


16


私があなたの靴の中にいたならば、ここで私が調査するであろういくつかの可能性があります:

  • このコードを複数のスレッドから実行している場合は、System.Net.ServicePointManager.DefaultConnectionLimitプロパティにぶつかる可能性があります。 アプリを起動したら、50〜100に増やしてみてください。 私はこれがあなたの問題だとは思わないことに注意してください、しかしこれを試すことは下記の他のものより簡単です。 :-)

  • もう一つの可能​​性はあなたがサーバーを圧倒しているということです。 これは通常シングルスレッドのクライアントでは困難ですが、他の複数のクライアントがサーバーにアクセスしている可能性があるため可能です。 しかし、この問題は常に#25で発生するため、これ以上のバリエーションが発生することが予想されるため、これはあまり考えられません。

  • クライアントとサーバー間でのキープアライブHTTP接続のバックアップで問題が発生している可能性があります。 これもまたありそうもないようです。

  • 25のハードカットオフは、これがあなたの側でもサーバー側でも、プロキシまたはファイアウォールの制限であると考えさせます。1つのクライアントIPから1つのサーバー(またはプロキシ)への25を超える接続が制限されます。

私のお金は後者のお金にあります、なぜならそれは常に要求のラウンド数がうまくいかないという事実と、デバッガに入ること(遅いことも!)が問題を引き起こさないからです。

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

それが遅れて消えてしまうのであれば、その理由を理解する必要があります。 サーバーのファイアウォールは変更できません) より多くの情報を得るために、あなたはリクエスト(例えば、 パターンが表示されるかどうかを確認するには、各呼び出しの前後にDateTimeを調べます。 タイミングが一貫していて突然大きくなった場合は、ネットワーク/ファイアウォール/プロキシの調整が必要です。 タイミングが次第に増える場合、それはサーバが次第に過負荷になり、そのリクエストキューを長くしていることを示唆しています。

リクエストのタイミングをとることに加えて、私はあなたのwebclient呼び出しのタイムアウトをもっと長く設定したので、タイムアウトが無限かデフォルトよりほんの少し長いかどうかを知ることができます。 これを行うには、タイムアウトをサポートしていないため、WebClientクラスに代わるものが必要です。 MSDNフォーラムの このスレッドには、妥当な代替コードのサンプルがあります。

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

  • fiddlerをダウンロードして起動します。

  • WebクライアントコードのProxyプロパティをfiddlerプロキシを指すように設定します(localhost:8888)

  • アプリを実行してフィドラーを見てください。


4


WebClient`はそれが使用する Response`オブジェクトを閉じていないようです。これはあなたの場合、同時に多数のレスポンスが開かれ、リモートサーバー上の接続数が25に制限されて、 'タイムアウト例外' あなたがデバッグするとき、早めに開かれた応答はそれらの内部タイムアウトなどのために閉じられます…​ (私は `WebClient`はReflectorでは応答を閉じるための指示が見つからないと思っていました)。

私はあなたが `HttpWebRequestを使うことを提案します

HttpWebRequestリクエスト。 HttpWebResponse response = null;

試してください{

FileStream fs;ストリームs。 byte []読み取り。 intカウント。

読み取り=新しいバイト[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){// .... }({response!= null)response.Close();}} {{{}} {{}}} {{{}}} {{}} {{}}} {{}} }


2


これがmanjiの答えを少し簡略化したものです。

プライベートstatic void DownloadFile(Uri remoteUri、文字列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); }}}


2


私は同じ問題を抱えています、そして私はそれを設定ファイルapp.configにこの行を追加することでそれを解決します: