2011-10-30 4 views
1

사이트의 http 응답 상태를 반환하는 스레드가 있지만 가끔 내 프로그램에서 false 결과를 반환합니다. 잠시 후에 좋은 결과를 얻습니다.
거짓 결과 : 는 그것을 확인하는 시간의 큰 마운트 소요되며, 다음 (예를 들어) 구글은 매우 합리적하지 않은, 다운 있다고하지만, 몇 초 후 좋은 결과C# false http 응답

을 반환

당신은보고 무엇이 잘못되었는지 말해 줄 수 있습니까? 또는 어떻게 개선 할 수 있습니까?
확인 데이터 그리드에있는 모든 사이트 :

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가 유효하지 않다는 의미는 아닙니다. 부인이 출산을하고 아이를 낳기를 기대하지만, 소녀가된다는 것은 잘못된 결과입니다. 그냥 예기치 못한 일.

그렇습니다 : 당신의 일을 분석하게하십시오 : 마침내 a 만 사이트를 확인하기 위해 오랜 시간이 걸린다면 ??? 결과는 200 응답 코드가 아닙니다. 우리는 당신이 시간 초과를 다루고 있다고 거의 거의 추측 할 수 있습니다. 사이에 귀하의 라우터, 구글이나 기본적인 네트워크 장치가 문제가 있다면, 그 예기치 않은 대답을 얻을 것으로 예상된다. "시간 초과", "잘못된 요청", "서버를 사용할 수 없음"등이 있습니다. 왜 이런 일이 발생합니까? 환경에 직접 액세스하지 않고도 확실하게 말할 수는 없습니다.

그러나 코드를 보면 백그라운드에서 각 검사를 작업에 사용하기 위해 기본 TaskScheduler를 사용하고 있음을 알 수 있습니다 (기본 작업 스케줄러가). 기본 작업 스케줄러는 스레드 풀에서 각 작업을 예약하므로 많은 작업이 동시에 실행됩니다. 여기에 우리는 네트워크 오버로딩을위한 좋은 후보자가 있습니다. 많은 사이트 (특히 google)는 동일한 출처 (특히 빈도가 높은 경우)에서 많은 요청을 처리하기 위해 다소 민감합니다. 따라서 Google이 일시적으로 사용자를 차단하거나 다시 반송하는 경우 일 수 있습니다. 다시 말하지만,이 시점에서 그것은 순수한 추측이지만, 모든 체크가 동시에 실행된다는 사실은 (스레드 풀이 최대치에 있지 않는 한) 문제의 원인 일 가능성이 큽니다.

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 이벤트 처리기에서 찾을 수 있습니다. 이는 결과를 가져 오기 전에 여러 작업이 완료 될 때까지 기다리는 방법을 분명히합니다. –