長い調査と検索の結果、非同期接続を設定し、希望するタイムアウト後に終了することで、おそらくやりたいことの方が役立つことを発見したと思います...しかし、私は行きますとにかく聞いてください!
コードの簡単なスニペット:
_HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(url);
webReq.Timeout = 5000;
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
// this takes ~20+ sec on servers that aren't on the proper port, etc.
_
マルチスレッドアプリケーションにあるHttpWebRequest
メソッドがあります。このメソッドでは、多数の会社のWebサーバーに接続しています。サーバーが応答しない場合、5秒のタイムアウトを指定したにもかかわらず、HttpWebRequest.GetResponse()
がタイムアウトするまでに約20秒かかります。定期的にサーバーを通過するために、接続に5秒以上かかるサーバーをスキップしたいと思います。
質問は次のとおりです。 "WebRequestまたはHttpWebRequestの接続タイムアウトを指定/減少する簡単な方法はありますか?"
Ibelieve問題は、WebRequest
が要求を実際に行った後にのみ時間を測定することです。同じアドレスに複数のリクエストを送信すると、ServicePointManager
はリクエストを抑制し、対応する ServicePoint.ConnectionLimit
デフォルトでは ServicePointManager.DefaultConnectionLimit
。アプリケーションCLRホストはこれを2に設定します。ASP Host to10。したがって、同じホストに複数の要求を送信するマルチスレッドアプリケーションがある場合、実際には2つだけがワイヤに配置され、残りはキューに入れられますアップ。
これが本当に起こるかどうかを決定的な証拠としてこれを調査したことはありませんが、同様のプロジェクトでは、ServicePoint
の制限を取り除くまで物事は恐ろしいものでした。
考慮すべきもう1つの要因は、DNSルックアップ時間です。繰り返しますが、私の信念は確固たる証拠に裏付けられていませんが、WebRequest
はnotリクエストタイムアウトに対してDNSルックアップ時間をカウントすると思います。 DNSルックアップ時間は、一部の展開では非常に大きな時間要因として表示される場合があります。
はい、アプリを WebRequest.BeginGetRequestStream
(コンテンツを含むPOST
sの場合)および WebRequest.BeginGetResponse
(GET
sの場合andPOSTS
s)。同期呼び出しはスケーリングされません(詳細については説明しませんが、その理由doには確固たる証拠があります)。とにかく、ServicePoint
の問題はこれに直行します。キューイング動作は非同期呼び出しでも発生します。
古いスレッドにタックしてすみませんが、上記のことは間違っている/誤解を招く可能性があると思います。
私が知ることができることから、タイムアウトは接続時間ではなく、HttpWebRequestと応答の寿命全体に許可されている合計時間です。証明:
設定します:
.Timeout=5000
.ReadWriteTimeout=32000
HttpWebRequestの接続およびポスト時間は26ミリ秒かかりました
しかし、その後のHttpWebRequest.GetResponse()の呼び出しは4974msでタイムアウトしたため、5000msが送信要求/応答の取得の呼び出しセット全体の時間制限であることを証明しました。
DNSの名前解決が時間の一部として測定されたかどうかは確認しませんでした。これは、これが実際に必要な方法で機能しないためです。要求の接続フェーズ中に失敗したことからわかるように、接続を受け入れていませんでした。
たとえば、結果を返す可能性のある接続要求で30秒待機しますが、不正な動作をしているホストに要求を送信するのを待機しているのは10秒だけです。
後で助けになったものは、.ReadWriteTimeout
プロパティです。これは、.Timeout
プロパティに加えて、スレッドが問題のあるサーバーからのダウンロードに費やす時間を最終的に削減したようです。 .ReadWriteTimeout
のデフォルトの時間は5分で、これは私のアプリケーションでは長すぎます。
だから、それは私には思えます:
.Timeout
=接続の確立の試行に費やした時間(ルックアップ時間を除く).ReadWriteTimeout
=接続の確立後のデータの読み取りまたは書き込みの試行に費やした時間
詳細: HttpWebRequest.ReadWriteTimeoutプロパティ
編集:
@KyleMのコメントによると、Timeout
プロパティは接続試行全体に対するものであり、MSDNでそれを読んでいます:
タイムアウトは、GetResponseメソッドを使用して行われた後続の同期要求が応答を待機し、GetRequestStreamメソッドがストリームを待機するミリ秒数です。 タイムアウトは、GetRequestStreamおよびGetResponseメソッド呼び出しに個別にではなく、リクエストとレスポンス全体に適用されます。タイムアウト期間内にリソースが返されない場合、リクエストは、StatusプロパティをWebExceptionStatus.Timeoutに設定してWebExceptionをスローします。
(エンファシス鉱山。)
HttpWebRequest.Timeoutプロパティのドキュメントから:
ドメインネームシステム(DNS)クエリが返されるか、タイムアウトになるまでに最大15秒かかる場合があります。リクエストに解決が必要なホスト名が含まれ、タイムアウトを15秒未満の値に設定した場合、リクエストのタイムアウトを示すためにWebExceptionがスローされるまでに15秒以上かかる場合があります。
DNSクエリがタイムアウトの原因である可能性はありますか?
私たちが何を試みたとしても、チェックしているサーバーがダウンしたときに21秒未満のタイムアウトを得ることができませんでした。
これを回避するために、TcpClientチェックを組み合わせてドメインが生きているかどうかを確認し、続いてURLがアクティブかどうかを確認する別のチェックを組み合わせました
public static bool IsUrlAlive(string aUrl, int aTimeoutSeconds)
{
try
{
//check the domain first
if (IsDomainAlive(new Uri(aUrl).Host, aTimeoutSeconds))
{
//only now check the url itself
var request = System.Net.WebRequest.Create(aUrl);
request.Method = "HEAD";
request.Timeout = aTimeoutSeconds * 1000;
var response = (HttpWebResponse)request.GetResponse();
return response.StatusCode == HttpStatusCode.OK;
}
}
catch
{
}
return false;
}
private static bool IsDomainAlive(string aDomain, int aTimeoutSeconds)
{
try
{
using (TcpClient client = new TcpClient())
{
var result = client.BeginConnect(aDomain, 80, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(aTimeoutSeconds));
if (!success)
{
return false;
}
// we have connected
client.EndConnect(result);
return true;
}
}
catch
{
}
return false;
}