2011-10-30 41 views
1

我有一个线程返回站点的http响应状态,但有时我的程序返回错误结果。过了一段时间,它会给出好的结果。
假结果: 它需要一个大的安装的时间来检查,然后它说,(例如)谷歌是下降,这是很不合理的,但几秒钟后返回了良好的效果C#false http响应

你可以看看,并告诉我什么是错的?或我该如何改进它?
检查DataGrid中的所有站点:

private void CheckSites() 
     { 
      if (CheckSelected()) 
      { 
       int rowCount = dataGrid.BindingContext[dataGrid.DataSource, dataGrid.DataMember].Count; 
       string url; 
       for (int i = 0; i < rowCount; i++) 
       { 
        url = dataGrid.Rows[i].Cells[2].Value.ToString(); 
        if (url != null) 
        { 
         Task<string[]> task = Task.Factory.StartNew<string[]> 
         (() => checkSite(url)); 

         // We can do other work here and it will execute in parallel: 
         //Loading... 

         // When we need the task's return value, we query its Result property: 
         // If it's still executing, the current thread will now block (wait) 
         // until the task finishes: 
         string[] result = task.Result; 
         selectRows(); 
         if (result[0] != System.Net.HttpStatusCode.OK.ToString() && result[0] != System.Net.HttpStatusCode.Found.ToString() && result[0] != System.Net.HttpStatusCode.MovedPermanently.ToString()) 
         { 
          //bad 
          notifyIcon1.ShowBalloonTip(5000, "Site Down", dataGrid.Rows[i].Cells[2].Value.ToString() + ", has a status code of:" + result, ToolTipIcon.Error); 
          dataGrid.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.Wheat; 
          TimeSpan ts; 
          TimeSpan timeTaken = TimeSpan.Parse(result[1]); 
          dataGrid.Rows[i].Cells[3].Value = result[0]; 
          dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.Red; 
          dataGrid.Rows[i].Cells[4].Value = timeTaken.Seconds.ToString() + "." + String.Format("{0:0.00000}", timeTaken.Milliseconds.ToString()) + " seconds."; 
          string sec = (DateTime.Now.Second < 10) ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString(); 
          string min = (DateTime.Now.Minute < 10) ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString(); 
          string hour = (DateTime.Now.Hour < 10) ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString(); 
          dataGrid.Rows[i].Cells[5].Value = hour + ":" + min + ":" + sec; 

          //loadbar 
         } 
         else if (result[0] == "catch")//catch 
         { 
          notifyIcon1.ShowBalloonTip(10000, "SITE DOWN", dataGrid.Rows[i].Cells[1].Value.ToString() + ", Error:" +result[1], ToolTipIcon.Error); 
          dataGrid.Rows[i].Cells[3].Value = result[1]; 
          dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.Red; 
          //loadbar 

         } 
         else 
         { 
          //good 
          TimeSpan timeTaken = TimeSpan.Parse(result[1]); 
          dataGrid.Rows[i].Cells[3].Value = result[0]; 
          dataGrid.Rows[i].Cells[3].Style.BackColor = System.Drawing.Color.LightGreen; 
          dataGrid.Rows[i].Cells[4].Value = timeTaken.Seconds.ToString() + "." + String.Format("{0:0.00000}", timeTaken.Milliseconds.ToString()) + " seconds."; 
          string sec = (DateTime.Now.Second < 10) ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString(); 
          string min = (DateTime.Now.Minute < 10) ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString(); 
          string hour = (DateTime.Now.Hour < 10) ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString(); 
          dataGrid.Rows[i].Cells[5].Value = hour + ":" + min + ":" + sec; 
          //loadbar 
         } 
         selectRows(); 
        } 
       } 
      } 
     } 

检查站点:

///////////////////////////////// 
     ////Check datagrid websites-button - returns response 
     ///////////////////////////////// 
     private string[] checkSite(string url) 
     { 
      string[] response = new string[2]; 
      url = dataGrid.Rows[0].Cells[2].Value.ToString(); 
      if (url != null) 
      { 
       try 
       { 
        HttpWebRequest httpReq; 


        httpReq.Timeout = 10000; 
        //loadbar 
        dataGrid.Rows[0].DefaultCellStyle.BackColor = System.Drawing.Color.Wheat; 
        System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); 
        timer.Start(); 
        HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse(); //httpRes.Close(); 
        timer.Stop(); 
        //loadbar 
        HttpStatusCode httpStatus = httpRes.StatusCode; 
        response[0] = httpStatus.ToString(); 
        response[1] = timer.Elapsed.ToString();//* 
        httpRes.Close(); 
        return response; 
       } 
       catch (Exception he) 
       { 
        response[0] = "catch"; 
        response[1] = he.Message; 
        return response; 
       } 
      } 
      response[0] = "catch"; 
      response[1] = "No URL entered"; 
      return response; 
      //dataGrid.Rows[i].DefaultCellStyle.BackColor = System.Drawing.Color.Blue; 

     } 

在此先感谢。

+2

请详细解释“虚假结果”和“好结果”的含义。 – Oded

+0

有多少网站正在并行检查? – Yahia

+0

这是否发生在整个计算机中?例如,如果您一次使用您的网络浏览器转到Google,它会再次失败吗? –

回答

1

假设提供的代码被用于实际的代码:

首先,你的“假结果”和“好结果”的定义是错误的。如果你期望A但得到B,那并不意味着B是无效的。如果你的妻子正在分娩,你希望有一个男孩,但结果是一个女孩,这不是一个错误的结果。意想不到的。

这就是说:让我们来分析一下你的工作:如果花了很长时间去检查一个网站才终于得到一个???结果这不是200响应代码。我们几乎可以保守地认为你正在处理超时。如果您的路由器,谷歌或其中任何基础网络设备出现问题,其预期会得到意想不到的答案。 “超时”,“错误的请求”,“服务器不可用”等。为什么会发生这种情况?如果没有直接访问您的环境,它是不可能说的。但是看看你的代码,我发现你使用了默认的TaskScheduler来让每次检查作为后台任务运行(假设你没有改变默认的任务调度器, )。默认任务调度程序调度线程池上的每个任务,这导致很多许多任务运行同步。这里我们有一个很好的候选人来重载你的网络。许多网站(尤其是谷歌)对于处理来自同一来源的许多请求(特别是如果频率很高)时相当敏感,所以也许谷歌暂时阻止你或阻止你回来。同样,在这一点上,它是纯粹的推测,但事实上,你同时运行所有检查(除非线程池在他的最大值)很可能是你的问题的原因。

UPDATE

我会建议用LimitedConcurrencyTaskScheduler工作(见这里:http://blogs.msdn.com/b/pfxteam/archive/2010/04/09/9990424.aspx)。在这里,您可以限制异步运行的任务数量。你必须做一些测试,以确定在你的情况下理想的数字。还要确保频率不是太“太高”。很难定义什么太高,只有测试才能证明这一点。

+0

是的,我认为Google是问题所在,如果我可以补充一点,那么在检查时,为了解冻程序,您会推荐做些什么? – funerr

+0

@ agam360 - 我更新了我的答案。这对你有帮助吗? – Polity

+0

最后,你认为我的代码可能返回不正确的响应时间吗? – funerr

0

为了模拟您的场景,我创建了一个带有数据网格和按钮的Winform。在窗体加载时,我以编程方式创建url列表(在表中)并绑定到数据网格。然后点击按钮,我们开始下载过程。简而言之,你必须编写更多的防御性代码,下面的代码只是解决问题的一个框架。

using System; 
using System.Data; 
using System.Net; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace app 
{ 
    public partial class Form1 : Form 
    { 
     DataTable urls = new DataTable(); 
     public Form1() 
     { 
      InitializeComponent(); 
     } 
     //Fill your uri's and bind to a data grid. 
     void InitTable() 
     { 
      //Silly logic to simulate your scenario. 
      urls = new DataTable(); 
      urls.Columns.Add(new DataColumn("Srl", typeof(string))); 
      urls.Columns.Add(new DataColumn("Urls", typeof(Uri))); 
      urls.Columns.Add(new DataColumn("Result", typeof(string))); 

      DataRow dr = urls.NewRow(); 
      dr["Srl"] = "1"; 
      dr["Urls"] = new Uri("http://www.microsoft.com"); 
      dr["Result"] = string.Empty; 
      urls.Rows.Add(dr); 
      dr = urls.NewRow(); 
      dr["Srl"] = "2"; 
      dr["Urls"] = new Uri("http://www.google.com"); 
      dr["Result"] = string.Empty; 
      urls.Rows.Add(dr); 
      dr = urls.NewRow(); 
      dr["Srl"] = "3"; 
      dr["Urls"] = new Uri("http://www.stackoverflow.com"); 
      dr["Result"] = string.Empty; 
      urls.Rows.Add(dr); 
      urls.AcceptChanges(); 
     } 
     void UpdateResult() 
     { 
      dataGridView1.DataSource = urls; 
     } 

     //Important 
     // This example will freeze UI. You can avoid this while implementing 
     //background worker or pool with some event synchronization. I haven't covered those area since 
     //we are addressing different issue. Let me know if you would like to address UI freeze 
     //issue. Or can do it your self. 
     private void button1_Click(object sender, EventArgs e) 
     {    
      //Create array for Task to parallelize multiple download. 
      var tasks = new Task<string[]>[urls.Rows.Count]; 
      //Initialize those task based on number of Uri's 
      for(int i=0;i<urls.Rows.Count;i++) 
      { 
       int index = i;//Do not change this. This is to avoid data race 
       //Assign responsibility and start task. 
       tasks[index] = new Task<string[]>(
         () => checkSite(
          new TaskInput(urls.Rows[index]["Urls"].ToString(), urls.Rows[index]["Srl"].ToString()))); 
       tasks[index].Start(); 

      } 
      //Wait for all task to complete. Check other overloaded if interested. 
      Task.WaitAll(tasks); 

      //block shows how to access result from task 
      foreach (var item in tasks) 
      { 
       DataRow[] rows=urls.Select("Srl='"+item.Result[2]+"'"); 
       foreach (var row in rows) 
         row["Result"]=item.Result[0]+"|"+item.Result[1]; 
      } 
      UpdateResult(); 
     } 
     //This is dummy method which in your case 'Check Site'. You can have your own 
     string[] checkSite(TaskInput input) 
     { 
      string[] response = new string[3]; 
      if (input != null) 
      { 
       try 
       { 
        WebResponse wResponse = WebRequest.Create(input.Url).GetResponse(); 

        response[0] = wResponse.ContentLength.ToString(); 
        response[1] = wResponse.ContentType; 
        response[2] = input.Srl; 
        return response; 
       } 
       catch (Exception he) 
       { 
        response[0] = "catch"; 
        response[1] = he.Message; 
        response[2] = input.Srl; 
        return response; 
       } 
      } 
      response[0] = "catch"; 
      response[1] = "No URL entered"; 
      response[2] = input.Srl; 
      return response; 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      InitTable(); 
      UpdateResult(); 
     } 
    } 
    //Supply custom object for simplicity 
    public class TaskInput 
    { 
     public TaskInput(){} 
     public TaskInput(string url, string srl) 
     { 
      Url = url; 
      Srl = srl; 
     } 
     public string Srl { get; set; } 
     public string Url { get; set; } 
    } 
} 
+0

谢谢,但那不是我想要做的(我不想下载文件)。 – funerr

+0

@ agam360:下载只是为了模拟您的场景,而不是解决您的问题。我的问题的答案可以在button1_Click事件处理程序中找到,这显然表明如何在获取结果之前等待多个任务完成。 –