Ajustement de la durée de connexion HttpWebRequest en C#
je crois qu'après de longues recherches et recherches, j'ai découvert que ce que je veux faire est probablement mieux servi en mettant en place une connexion asynchrone et en y mettant fin après le délai souhaité... Mais je vais aller de l'avant et demander de toute façon!
Rapide extrait de code:
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.
j'ai une méthode HttpWebRequest
qui est dans une application multi-filetée, dans laquelle je me connecte à un grand nombre d'entreprise serveurs web. Dans les cas où le serveur ne répond pas, le HttpWebRequest.GetResponse()
prend environ 20 secondes pour s'arrêter, même si j'ai spécifié un délai de seulement 5 secondes. Dans l'intérêt de passer par les serveurs sur un intervalle régulier, je veux ignorer ceux qui prennent plus de 5 secondes pour se connecter à.
alors la question Est: " Existe-t-il une façon simple de spécifier/diminuer un délai de connexion pour une WebRequest ou une HttpWebRequest?"
5 réponses
je croire que le problème est que le WebRequest
mesure le temps seulement après que la demande est faite. Si vous soumettez plusieurs requêtes à la même adresse, alors le ServicePointManager
va étouffer vos requêtes et ne soumet réellement autant de connexions simultanées que la valeur de la correspondante ServicePoint.ConnectionLimit
qui par défaut obtient la valeur de ServicePointManager.DefaultConnectionLimit
. Application CLR host sets ici à 2, ASP host à 10. Donc, si vous avez une application multithread qui soumet plusieurs requêtes à la même machine, seulement deux sont réellement placées sur le fil, le reste est en file d'attente.
Je n'ai pas cherché cette preuve concluante si c'est vraiment ce qui se passe, mais sur un projet similaire j'ai eu des choses étaient horribles jusqu'à ce que j'ai enlevé la limitation ServicePoint
.
un autre facteur à considérer est le temps de recherche DNS. Encore une fois, est mon croyance non soutenue par des preuves tangibles, mais je pense que le WebRequest
ne pas compter le temps de recherche DNS contre le délai de demande. Le temps de recherche DNS peut apparaître comme un facteur de temps très important dans certains déploiements.
et oui, vous devez coder votre application autour de la WebRequest.BeginGetRequestStream
(pour POST
s avec contenu) et WebRequest.BeginGetResponse
(pour GET
s et POSTS
s). Les appels synchrones ne seront pas échelle (Je ne vais pas entrer dans les détails pourquoi, mais que je do ont des preuves tangibles pour). Quoi qu'il en soit, la question ServicePoint
est orthogonale à ceci: le comportement de mise en file d'attente se produit avec les appels asynchrones aussi.
désolé de vous accrocher à un vieux fil, mais je pense que quelque chose qui a été dit ci-dessus peut être incorrect/trompeur.
D'après ce que je peux dire .Timeout n'est pas le temps de connexion, c'est le temps total alloué pour toute la vie du HttpWebRequest et de la réponse. Preuve:
J'Ai Mis:
.Timeout=5000
.ReadWriteTimeout=32000
Le connecter et poster de temps pour la HttpWebRequest a pris 26ms
mais l'appel suivant HttpWebRequest.GetResponse () chronométré dans 4974ms prouvant ainsi que les 5000ms étaient la limite de temps pour l'ensemble des appels de send request/get response.
Je n'ai pas vérifié si la résolution du nom DNS a été mesurée en temps partiel car cela ne me concerne pas car cela ne fonctionne pas de la façon dont j'en ai vraiment besoin pour fonctionner--mon intention était de me déconnecter plus rapidement lorsque je me connecte à des systèmes qui n'acceptent pas les connexions comme le montre leur défaillance lors de la phase de connexion du DNS. demande.
par exemple: je suis prêt à attendre 30 secondes sur une requête de connexion qui a une chance de retourner un résultat, mais je ne veux brûler que 10 secondes en attendant d'envoyer une requête à un hôte qui se comporte mal.
quelque chose que j'ai trouvé plus tard qui a aidé, est la propriété .ReadWriteTimeout
. Cela, en plus de la propriété .Timeout
semblait finalement réduire le temps que les threads passeraient à essayer de télécharger à partir d'un serveur problématique. Le temps par défaut pour .ReadWriteTimeout
est de 5 minutes, ce qui pour mon application était beaucoup trop long.
ainsi, il me semble:
.Timeout
= temps passé à essayer d'établir une connexion (sans compter le temps de recherche))
.ReadWriteTimeout
= temps passé à essayer de lire ou d'écrire des données après l'établissement de la connexion
Plus d'infos: HttpWebRequest.Readwritetimeout Propriété
Edit:
selon le commentaire de @KyleM, la propriété Timeout
est pour toute la tentative de connexion, et la lecture sur elle à MSDN montre:
Timeout est le nombre de millisecondes qu'un la requête synchrone subséquente faite avec la méthode GetResponse attend une réponse, et la méthode GetRequestStream attend un flux. le délai s'applique à l'ensemble de la requête et de la réponse, pas individuellement aux appels de la méthode GetRequestStream et GetResponse. si la ressource n'est pas retournée dans le délai imparti, la requête lance une WebException avec la propriété Status définie à WebExceptionStatus.Timeouts.
(italique) mine.)
de la documentation du HttpWebRequest.Propriété de Timeout:
une requête DNS (Domain Name System) peut prendre jusqu'à 15 secondes pour retourner ou le temps. Si votre demande contient nom d'hôte nécessitant une résolution et vous réglez le délai à une valeur inférieure à 15 secondes, cela peut prendre 15 secondes ou plus avant Qu'une WebException ne soit lancée pour indiquer un délai sur votre demande.
est-il possible que votre La requête DNS est la cause de la temporisation?
peu importe ce que nous avons essayé, nous n'avons pas réussi à obtenir le délai en dessous de 21 secondes lorsque le serveur que nous vérifions était en panne.
pour contourner cela, nous avons combiné une vérification TcpClient pour voir si le domaine était vivant suivi d'une vérification séparée pour voir si L'URL était active
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;
}