HttpWebRequest限制?或者执行不好

时间:2009-07-14 02:55:32

标签: c# httpwebrequest

我正在尝试构建一个c#控制台应用程序,它将监控大约3000个网址(只需知道HEAD请求返回200,不一定是内容等)

我在这里的尝试是构建一个例程来检查web URLS,循环并创建每个执行例程的线程。发生的事情是如果我使用< 20个线程运行,它大部分时间都执行正常,但如果我使用> 20个线程,那么一些url会超时。我尝试将Timeout增加到30秒,同样发生。我运行此网络的网络能够执行50个HTTP HEAD请求(ISP的10MBIT连接),并且在执行例程时CPU和网络都运行得非常低。

当发生超时时,我在浏览器上测试相同的IP并且工作正常,我反复测试了这一点,并且在测试期间从未出现过“超时”网址实际超时的情况。

我想运行> 20个线程的原因是我想每5分钟执行一次这个测试,其中一些URL需要整整10秒(如果超时设置得更高,则更高),我想确保它能够在2-3分钟内运行所有URL。

是否有更好的方法来检查网址是否可用,或者我是否应该查看系统/网络是否存在问题。

MAIN

        while (rdr.Read())
        {
            Thread t = new Thread(new ParameterizedThreadStart(check_web));

            t.Start(rdr[0]);


        }

      static void check_web(object weburl)
      {
          bool isok;
          isok = ConnectionAvailable(weburl.ToString());
      }



      public static bool ConnectionAvailable(string strServer)
      {

          try
          {
              strServer = "http://" + strServer;
              HttpWebRequest reqFP = (HttpWebRequest)HttpWebRequest.Create(strServer);
              reqFP.Timeout = 10000;
              reqFP.Method = "HEAD";

              HttpWebResponse rspFP = (HttpWebResponse)reqFP.GetResponse();
              if (HttpStatusCode.OK == rspFP.StatusCode)
              {
                  Console.WriteLine(strServer + " - OK");
                  rspFP.Close();
                  return true;
              }
              else
              {
                  Console.WriteLine(strServer + " Server returned error..");
                  rspFP.Close();
                  return false;

              }

          }

          catch (WebException x)
          {
              if (x.ToString().Contains("timed out"))
              {
                  Console.WriteLine(strServer + " - Timed out");
              }
              else
              {
                  Console.WriteLine(x.Message.ToString());
              }

              return false;

          }

      }

3 个答案:

答案 0 :(得分:8)

记住,你问过。

非常糟糕的实施。

  1. 不要去创建那样的线程。拥有比处理器内核更多的线程确实没什么用。额外的线程几乎只会相互竞争,特别是因为它们都运行相同的代码。

  2. 您需要使用块实现。如果你抛出异常(很有可能),那么你将会泄漏资源。

  3. 归还布尔的目的是什么?你在某处检查吗?在任何情况下,您的错误和异常处理都是一团糟。

    • 当您收到非200响应时,您不会显示错误代码。
    • 您正在与Message属性进行比较,以确定它是否为超时。微软应该在“时间”和“外出”之间留一个空格来惹恼你。
    • 当它不是超时时,只显示Message属性,而不是整个异常,Message属性已经是一个字符串,不需要你调用ToString()。
  4. 下一批变更

    这没有完成,我不这么认为,但试试这个:

    public static void Main()
    {
        // Don't mind the interpretation. I needed an excuse to define "rdr"
        using (var conn = new SqlConnection())
        {
            conn.Open();
            using (var cmd = new SqlCommand("SELECT Url FROM UrlsToCheck", conn))
            {
                using (var rdr = cmd.ExecuteReader())
                {
                    while (rdr.Read())
                    {
                        // Use the thread pool. Please.
                        ThreadPool.QueueUserWorkItem(
                            delegate(object weburl)
                                {
                                    // I invented a reason for you to return bool
                                    if (!ConnectionAvailable(weburl.ToString()))
                                    {
                                        // Console would be getting pretty busy with all
                                        // those threads
                                        Debug.WriteLine(
                                            String.Format(
                                                "{0} was not available",
                                                weburl));
                                    }
                                },
                                rdr[0]);
                    }
                }
            }
        }
    }
    
    public static bool ConnectionAvailable(string strServer)
    {
        try
        {
            strServer = "http://" + strServer;
            var reqFp = (HttpWebRequest)WebRequest.Create(strServer);
            reqFp.Timeout = 10000;
            reqFp.Method = "HEAD";
    
            // BTW, what's an "FP"?
            using (var rspFp = (HttpWebResponse) reqFp.GetResponse()) // IDisposable 
            {
                if (HttpStatusCode.OK == rspFp.StatusCode)
                {
                    Debug.WriteLine(string.Format("{0} - OK", strServer));
                    return true; // Dispose called when using is exited
                }
    
                // Include the error because it's nice to know these things
                Debug.WriteLine(String.Format(
                     "{0} Server returned error: {1}", 
                     strServer, rspFp.StatusCode));
                return false;
            }
        }
        catch (WebException x)
        {
            // Don't tempt fate and don't let programs read human-readable messages
            if (x.Status == WebExceptionStatus.Timeout)
            {
                Debug.WriteLine(string.Format("{0} - Timed out", strServer));
            }
            else
            {
                // The FULL exception, please
                Debug.WriteLine(x.ToString());
            }
    
            return false;
        }
    }
    

    几乎完成 - 未经深夜编码测试

    public static void Main()
    {
        using (var conn = new SqlConnection())
        {
            conn.Open();
            using (var cmd = new SqlCommand("", conn))
            {
                using (var rdr = cmd.ExecuteReader())
                {
                    if (rdr == null)
                    {
                        return;
                    }
    
                    while (rdr.Read())
                    {
                        ThreadPool.QueueUserWorkItem(
                            CheckConnectionAvailable, rdr[0]);
                    }
                }
            }
        }
    }
    
    private static void CheckConnectionAvailable(object weburl)
    {
        try
        {
            // If this works, it's a lot simpler
            var strServer = new Uri("http://" + weburl);
            using (var client = new WebClient())
            {
                client.UploadDataCompleted += ClientOnUploadDataCompleted;
                client.UploadDataAsync(
                    strServer, "HEAD", new byte[] {}, strServer);
            }
        }
        catch (WebException x)
        {
            Debug.WriteLine(x);
        }
    }
    
    private static void ClientOnUploadDataCompleted(
        object sender, UploadDataCompletedEventArgs args)
    {
        if (args.Error == null)
        {
            Debug.WriteLine(string.Format("{0} - OK", args.UserState));
        }
        else
        {
            Debug.WriteLine(string.Format("{0} - Error", args.Error));
        }
    }
    

答案 1 :(得分:1)

使用ThreadPool课程。不要像这样产生数百个线程。线程有如此巨大的开销,在你的情况下会发生的事情是你的CPU将花费99%的时间用于上下文切换,1%用于实际工作。

答案 2 :(得分:1)

不要使用线程。

Asynch Call backs and queues。为什么在他们都想要的资源访问外部世界时创建一个线程。将线程限制为大约5,然后实现使用队列的类。将代码分为两部分,即提取和进程。一个控制数据流,另一个控制对外界的访问。

使用您喜欢的任何语言,但如果您认为线程用于处理和数字运算并且异步回调用于资源管理,则不会出错。