2010-02-18 6 views
2
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseurl + url); 
req.Timeout = 1000 * 10; 
HttpWebResponse response = (HttpWebResponse)req.GetResponse(); 
Stream str = response.GetResponseStream(); 
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument(); 
doc.Load(str); 
response.Close(); 
string imgurl = doc.DocumentNode.SelectSingleNode("//div[@class='one-page']/a/img[@class='manga-page']").Attributes["src"].Value; 
req = (HttpWebRequest)HttpWebRequest.Create(imgurl); 
req.Timeout = 1000 * 10; 
response = (HttpWebResponse)req.GetResponse(); 
str = response.GetResponseStream(); 
Image img = Image.FromStream(str); 
response.Close(); 
return img; 

Je lance ce code dans une boucle (en utilisant plusieurs threads) pour télécharger environ 4000 images, et cela fonctionne brillamment pour les premières centaines mais ensuite (à un moment différent à chaque fois que j'essaie) il cesse soudain de fonctionner, et chaque appel à "req.GetResponse()" entraîne une exception TimeoutException. Je n'ai aucune idée de pourquoi cela arrive et aucune idée de ce qui pourrait être mauvais ou comment y faire face. Toute aide serait très appréciée.Webrequest cesse de fonctionner

Le code que j'utilise pour exécuter cette fonction (il est appelé GetPage (int) et appelé c.GetPage (t)) est la suivante:

for (int j = 0; j < 2; j++) 
{ 
    BackgroundWorker bw = new BackgroundWorker(); 
    num[bw] = j; 
    bgs.Add(bw); 
    bw.DoWork += (object sender, DoWorkEventArgs doargs) => 
    { 
     int t = -1; 
     lock (lockObjForQueueOperations) 
     { 
      if (images.Count != 0) 
       t = images.Dequeue(); 
     } 
     if(t < 0) 
     { 
      doargs.Result = false; 
      return; 
     } 
     currently[sender] = t; 
     Image img; 
     try { img = c.GetPage(t); } 
     catch (Exception e) 
     { 
      lock (lockObjForQueueOperations) 
      { 
       images.Enqueue(t); 
      } 
      lock (Console.Title) 
      { 
       if (num[sender] == 0) Console.ForegroundColor = ConsoleColor.Cyan; 
       else if (num[sender] == 1) Console.ForegroundColor = ConsoleColor.Yellow; 
       Console.WriteLine("**ERR: Error fetshing page {0}, errormsg: {1}", t, e.Message); 
       Console.ForegroundColor = ConsoleColor.White; 
      } 
      doargs.Result = true; 
      Thread.Sleep(1000*2); 
      return; 
     } 
     lock (Console.Title) 
     { 
      if (num[sender] == 0) Console.ForegroundColor = ConsoleColor.Cyan; 
      else if (num[sender] == 1) Console.ForegroundColor = ConsoleColor.Yellow; 
      Console.WriteLine("\t\tLoaded page {0} of {1}.", t + 1, c.PagesCount); 
      Console.ForegroundColor = ConsoleColor.White; 
     } 
     string imgpath = Path.Combine(ndir, "Page " + (t + 1) + ".png"); 
     img.Save(imgpath, System.Drawing.Imaging.ImageFormat.Png); 
     img.Dispose(); 
     doargs.Result = true; 
    }; 
    bw.RunWorkerCompleted += (object sender, RunWorkerCompletedEventArgs runargs) => 
    { 
     if ((bool)runargs.Result) bw.RunWorkerAsync(); 
     else 
     { 
      finnishedworkers++; 
      if (finnishedworkers == 2) restetter.Set(); 
      bw.Dispose(); 
     } 
    }; 
    bw.RunWorkerAsync(); 
} 
+1

Cela est probablement dû à la protection DDOS de votre FAI ou de l'hôte du site Web. – SLaks

+0

Eh bien, c'est ce que je pensais au début, mais j'ai ensuite essayé d'entrer dans la même page que mon programme essayait d'entrer à partir de mon navigateur, et cela a fonctionné, mais mon programme a encore des délais. – Alxandr

+0

@Alxandr, je suis confronté au même problème. Avez-vous trouvé une solution à ce problème? – Somnath

Répondre

2

La propriété dans le délai d'attente est HttpWebRequest en millisecondes. Le réglage actuel à 10 000 n'est que de 10 secondes, ce qui peut ne pas être suffisant en fonction de la bande passante et de la taille des données tirées, ainsi que de la complexité du code exécuté. Je dis essayer d'augmenter cela en premier.

+0

Les ressources sont chargées en une seconde. J'ai mis le temps mort parce que j'étais fatigué d'attendre mes timeoutxceptions. – Alxandr

+0

J'ai aussi essayé d'exécuter le code sans paramétrer le timeout, mais il m'a fallu trop longtemps pour me donner les exceptions (j'attendais juste les exceptions, rien ne se passait du tout ...). – Alxandr

2

Vous avez un mauvais design. Au lieu de créer des threads pour chaque requête, essayez d'appeler BeginGetResponse. Le framework gérera l'allocation de threads à partir du pool de threads pour répondre à vos demandes.

Ajouter un appel à ServicePointManager.SetDefaultConnectionLimit (?) Pas sûr de ce à un même nombre 100.

créer un sémaphores avec un nombre correspondant au nombre limite de connexion.

Dans votre fonction qui appelle BeginGetResponse ajouter un appel à semaphore.WaitOne() juste avant l'appel se BeginGet ...

Dans votre gestionnaire EndGetResponse(), appelez semaphore.Release() pour permettre à la prochaine demande continuer.

Vous utilisez probablement le pool de threads avec tous vos propres threads. Surveillez votre processus et voyez si vous ne pouvez pas exécuter et n'utilisez que 5 à 10 threads au total, jamais. Peut-être que vous pourriez enregistrer Thread.Current.ThreadID pour voir comment le thread SAME gère plusieurs demandes.

Fait des milliards de fois. Vraiment.

+0

Je ne pense pas que je suis épuiser le threadpool avec seulement 3 threads en cours d'exécution à tous les temps? Ou le background-worker crée-t-il un nouveau thread chaque fois que "RunWorkerAsync" est appelé? – Alxandr

Questions connexes