のTAP パターンAPI を使用して作成された Web クローラーですHttpWebRequest
。
からいくつかのものをダウンロードしたいのですがhttp://somedomain.tld
、かなりの数のリクエストを送信することになるかもしれません。がタイムリーに応答するかどうかはわかりませんsomedomain.tld
。応答の返送が完了するまで、要求ごとに 10 秒以内に収めたいと考えています。ServicePoint
また、そのドメインに対してによって適用される接続制限も利用したいと考えています。
そのため、リクエストでタイムアウトできる必要があります。通常、次からキャンセル トークンを取得しますCancellationTokenSource
。
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10d))
それを非同期操作に提供し、おそらく を呼び出すキャンセル コールバックも登録するmyWebRequest.Abort()
ので、最終的には次のような (簡略化された) メソッドになります。
public async Task<byte[]> GetResponseData(Uri uri, CancellationToken ct)
{
var wr = (HttpWebRequest)WebRequest.Create(uri);
ct.Register(wr.Abort);
using(var response = await wr.GetResponseAsync())
using(var ms = new MemoryStream())
using(var responseStream = response.GetResponseStream())
{
await responseStream.CopyToAsync(ms,4096,ct);
return ms.ToArray();
}
}
ここまでは順調ですね。
少し制限させてください。
var uri = new Uri("http://somedomain.tld");
var sp = ServicePointManager.FindServicePoint(uri);
sp.ConnectionLimit = 1;
現在、ServicePoint
関連付けられているインスタンスsomedomain.tld
は、一度に 1 つのリクエストのみを許可します。
ここで、2 つのリクエストを同時に送信します。これによりServicePoint
、ターゲット ドメインが私の悪用から隔離されることがわかっているので安全です。
var dataTasks = Enumerable.Range(0,2).Select(async _=>{
using(var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10d)))
{
return await GetResponseData(uri,cts.Token);
}
});
var datas = await Task.WhenAll(dataTasks);
ここで、最初のリクエストが完了するまでに 10 秒以上かかると仮定しましょう...ServicePoint
一度に 1 つのリクエストのみを起動するように制約しているため、ServicePoint
が 2 番目のリクエストを起動するまでに、それはすでにキャンセルされており、中止されました。
では、リクエストが実際にいつ送信されているかを知るにはどうすればよいでしょうか? ServicePoint
特定のリクエストに関するのアクションを「認識する」タイムアウトを設定するにはどうすればよいですか?