2012-06-13 26 views
7

Ich versuche, meinen eigenen einfachen Web-Crawler zu machen. Ich möchte Dateien mit bestimmten Erweiterungen von einer URL herunterladen. Ich habe den folgenden Code geschrieben:Warum ist die Anzahl gleichzeitiger Downloads begrenzt?

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     if (bw.IsBusy) return; 
     bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
     bw.RunWorkerAsync(new string[] { URL.Text, SavePath.Text, Filter.Text }); 
    } 
    //-------------------------------------------------------------------------------------------- 
    void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     try 
     { 
      ThreadPool.SetMaxThreads(4, 4); 
      string[] strs = e.Argument as string[]; 
      Regex reg = new Regex("<a(\\s*[^>]*?){0,1}\\s*href\\s*\\=\\s*\\\"([^>]*?)\\\"\\s*[^>]*>(.*?)</a>", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); 
      int i = 0; 
      string domainS = strs[0]; 
      string Extensions = strs[2]; 
      string OutDir = strs[1]; 
      var domain = new Uri(domainS); 
      string[] Filters = Extensions.Split(new char[] { ';', ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); 
      string outPath = System.IO.Path.Combine(OutDir, string.Format("File_{0}.html", i)); 

      WebClient webClient = new WebClient(); 
      string str = webClient.DownloadString(domainS); 
      str = str.Replace("\r\n", " ").Replace('\n', ' '); 
      MatchCollection mc = reg.Matches(str); 
      int NumOfThreads = mc.Count; 

      Parallel.ForEach(mc.Cast<Match>(), new ParallelOptions { MaxDegreeOfParallelism = 2, }, 
      mat => 
      { 
       string val = mat.Groups[2].Value; 
       var link = new Uri(domain, val); 
       foreach (string ext in Filters) 
        if (val.EndsWith("." + ext)) 
        { 
         Download((object)new object[] { OutDir, link }); 
         break; 
        } 
      }); 
      throw new Exception("Finished !"); 

     } 
     catch (System.Exception ex) 
     { 
      ReportException(ex); 
     } 
     finally 
     { 

     } 
    } 
    //-------------------------------------------------------------------------------------------- 
    private static void Download(object o) 
    { 
     try 
     { 
      object[] objs = o as object[]; 
      Uri link = (Uri)objs[1]; 
      string outPath = System.IO.Path.Combine((string)objs[0], System.IO.Path.GetFileName(link.ToString())); 
      if (!File.Exists(outPath)) 
      { 
       //WebClient webClient = new WebClient(); 
       //webClient.DownloadFile(link, outPath); 

       DownloadFile(link.ToString(), outPath); 
      } 
     } 
     catch (System.Exception ex) 
     { 
      ReportException(ex); 
     } 
    } 
    //-------------------------------------------------------------------------------------------- 
    private static bool DownloadFile(string url, string filePath) 
    { 
     try 
     { 
      HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 
      request.UserAgent = "Web Crawler"; 
      request.Timeout = 40000; 
      WebResponse response = request.GetResponse(); 
      Stream stream = response.GetResponseStream(); 
      using (FileStream fs = new FileStream(filePath, FileMode.CreateNew)) 
      { 
       const int siz = 1000; 
       byte[] bytes = new byte[siz]; 
       for (; ;) 
       { 
        int count = stream.Read(bytes, 0, siz); 
        fs.Write(bytes, 0, count); 
        if (count == 0) break; 
       } 
       fs.Flush(); 
       fs.Close(); 
      } 
     } 
     catch (System.Exception ex) 
     { 
      ReportException(ex); 
      return false; 
     } 
     finally 
     { 

     } 
     return true; 
    } 

Das Problem ist, dass, während es für 2 parallele Downloads funktioniert gut:

 new ParallelOptions { MaxDegreeOfParallelism = 2, } 

... es ist nicht für größeren Grad an Parallelität wie funktioniert:

 new ParallelOptions { MaxDegreeOfParallelism = 5, } 

... und ich bekomme Verbindung Timeout Ausnahmen.

Zuerst dachte ich, es wegen WebClient war:

   //WebClient webClient = new WebClient(); 
       //webClient.DownloadFile(link, outPath); 

... aber wenn ich es mit der Funktion ersetzt DownloadFile, die die HttpWebRequest benutzte ich immer noch den Fehler.

Ich habe es auf vielen Webseiten getestet und nichts geändert. Ich habe auch mit der Chrome-Erweiterung "Download Master" bestätigt, dass diese Webserver mehrere parallele Downloads erlauben. Hat jemand eine Idee, warum ich Timeout-Ausnahmen bekomme, wenn ich versuche, viele Dateien parallel herunterzuladen?

+2

Nur neugierig: Warum werfen Sie eine Ausnahme, wenn die Arbeit erledigt ist? –

+0

http://stackoverflow.com/questions/866350/how-can-i-programmatical-remove-the-2-connection-limit-in-webclient –

+1

Die Ausnahme, die ich am Ende werfen, ist ein temporäres Stück Code. Ich musste schnell sehen, wann alles fertig war, also dachte ich "Warum nicht?". – NoOne

Antwort

1

Soweit ich weiß, IIS wird die Gesamtzahl der Verbindungen ein- und ausgrenzen, jedoch sollte diese Zahl im Bereich von 10^3 nicht ~ 5 liegen.

Ist es möglich, dass Sie von der gleichen URL testen? Ich weiß, dass viele Webserver die Anzahl gleichzeitiger Verbindungen von Clients begrenzen. Bsp: Testen Sie, indem Sie versuchen, 10 Kopien von http://www.google.com herunterzuladen?

Wenn so möchten Sie vielleicht Tests mit einer Liste von verschiedenen Standorten versuchen, wie zum Beispiel:

Verwandte Themen