2015-01-20 4 views
0

많은 수의 IP 주소를 동시에 ping하기 위해이 프로그램을 작업하고 있습니다. 한 번에 하나씩 각 주소에 핑을 시도했지만 일단 50 개 이상의 호스트에 ping을 시작하면 광기가 오래갑니다. 내가 가지고있는 문제는 취소 버튼 클릭시 비동기 스레드를 중지 할 수 없어 하나 이상의 호스트를 핑 (ping) 할 때이 오류가 발생한다는 것입니다. 나는 그것을 알아낼려고 2 일을 보내고 행운이 없었다. 다음과 같이 정확한 오류는 다음과 같습니다 당신이 당신의 루프에서 모두 Ping.Send()Ping.SendAsync()를 호출하는 것을비동기 스레드가 멈추지 않습니다.

 
System.InvalidOperationException: An asynchronous call is already in 
progress. It must be completed or canceled before you can call this method. 
at System.Net.NetworkInformation.Ping.CheckStart(Boolean async) 
at System.Net.NetworkInformation.Ping.Send(IPAddress address, Int32 timeout, Byte[] buffer, PingOptions options) 
at MultiPing.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in f:\Dev\tfsMultiPing\Multi Ping\MultiPing\MultiPing\Form1.cs:line 139 
private void pingBtn_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      if (inputBox.Text == "") 
      { 
       MessageBox.Show("Please Enter an IP Address to Ping.",  "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 
      else 
      { 
       if (backgroundWorker1.IsBusy != true) 
       { 
        backgroundWorker1.RunWorkerAsync(); 
       } 
       else 
       { 
        MessageBox.Show("Please Cancel current Ping or wait  for it to be completed"); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 
    } 



    public void backgroundWorker1_DoWork(object sender,  System.ComponentModel.DoWorkEventArgs e) 
    { 
     try 
     { 
      this.Invoke(new MethodInvoker(delegate {  progressBar1.Enabled = true; })); 
      int i; 

      //Add each line in the input box to the "allLines" string  array 
      string[] allLines = inputBox.Lines; 
      Ping pingSender = new Ping(); 

      try 
      { 
       //Get an object that will block the main thread 
       AutoResetEvent waiter = new AutoResetEvent(false); 

       //When the PingCompleted even is raised, 
       //The PingCompletedCallback method is called. 
       pingSender.PingCompleted += new  PingCompletedEventHandler(PingCompletedCallback); 

       //Create a buffer of 32 bytes of data to be transmitted. 
       string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 
       byte[] buffer = Encoding.ASCII.GetBytes(data); 

       //Wait 2 seconds for a reply. 
       int timeout = 2000; 

       //Set Options for transmission: 
       //The data can go through 64 gateways or routers 
       //before it is destroyed, and the data packet 
       //cannot be fragmented 
       PingOptions options = new PingOptions(64, true); 

       //Check if Cancel Button was clicked 
       if (backgroundWorker1.CancellationPending == true) 
       { 
        e.Cancel = true; 
        return; 
       } 
       else 
       { 
        //Begin Loop to ping each given IP Address 
        for (i = 0; i < allLines.Length; i++) 
        { 
         //Check if Cancel Button was clicked 
         if (backgroundWorker1.CancellationPending ==  true) 
         { 
          e.Cancel = true; 
          return; 
         } 
         else 
         { 
          //Convert each line from the input box to an  IP address 
          IPAddress address =  IPAddress.Parse(allLines[i]); 

          //Send ping Asynchronously 
          //Use the waiter as the user token. 
          //When the callback complets, it can wake up  this thread. 
          pingSender.SendAsync(address, timeout,  buffer, options, waiter); 
          PingReply reply = pingSender.Send(address,  timeout, buffer, options); 
          waiter.WaitOne(); 
          //If a replay is recieved Print "IP Address"  is up in the output box. 
          if (reply.Status == IPStatus.Success) 
          { 
           this.Invoke(new MethodInvoker(delegate {  outputBoxLive.AppendText(address + " is up" + Environment.NewLine); })); 
          } 

          //If no reply is recieved then print "IP Address" is down in the output box. 
          else if (reply.Status == IPStatus.TimedOut) 
          { 
           this.Invoke(new MethodInvoker(delegate  {  outputBoxDown.AppendText(address + " is down" + Environment.NewLine); })); 
           pingSender.Dispose(); 
          } 

          pingSender.Dispose(); 
         } 
        } 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
      } 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 
    } 

    public void pingStuff() 
    { 
    } 

    private static void PingCompletedCallback(object sender,  PingCompletedEventArgs e) 
    { 
     //If the operation was cancelled, Display a message to the user 
     if (e.Cancelled) 
     { 
      MessageBox.Show("Ping Cancelled"); 

      //Let the main thread resume. 
      //User token is the AutoResetEvent object that the main  thread is waiting for 
      ((AutoResetEvent)e.UserState).Set(); 
     } 

     //If an error occurred, Display the exception to the user. 
     if (e.Error != null) 
     { 
      MessageBox.Show("Ping Failed: " + e.Error.ToString()); 

      //Let the main thread resume. 
      ((AutoResetEvent)e.UserState).Set(); 
     } 
     PingReply reply = e.Reply; 
     DisplayReply(reply); 

     //Let the main thread resume. 
     ((AutoResetEvent)e.UserState).Set(); 
    } 

    public static void DisplayReply(PingReply reply) 
    { 
     if (reply == null) 
      return; 

     Console.WriteLine("ping status: [0]", reply.Status); 
     if (reply.Status == IPStatus.Success) 
     { 
      Console.WriteLine("Address: {0}", reply.Address.ToString()); 
      Console.WriteLine("RoundTrip time: {0}",  reply.RoundtripTime); 
      Console.WriteLine("Time to live: {0}", reply.Options.Ttl); 
      Console.WriteLine("Don't fragment: {0}",  reply.Options.DontFragment); 
      Console.WriteLine("Buffer size: {0}", reply.Buffer.Length); 
     } 
    } 




    public void button2_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      backgroundWorker1.CancelAsync(); 
     } 
     catch (Exception exc) 
     { 
      Console.WriteLine(exc); 
     } 
    } 
} 
} 
+0

코드를 읽지 않고 아마도 취소 토큰을 async 메서드에 전달할 수 있습니다. – Alkasai

+0

포럼 사이트와 달리 우리는 "감사합니다"또는 "도움을 주셨으면"또는 [그래서]에 서명하지 않습니다. "[안녕하세요, '고마워,'태그 라인 및 인사말을 게시물에서 삭제해야합니까?] (http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be 참조) -removed-from-post) –

+0

'Invoke '를 호출하면 콜백에서'EndInvoke'를 호출해야합니다. – Mgetz

답변

0

코드 (예외의 즉 원인)과 즉각적인 문제입니다. Ping.SendAsync()을 호출했으면 Send() 또는 SendAsync()에 대한 이후의 모든 호출은 처음 SendAsync() 작업이 완료 될 때까지는 올바르지 않습니다.

왜 둘 다 가지고 있는지 명확하지 않습니다. 동 기적으로 전화를 걸고 싶다면 가장 간단한 방법은 SendAsync()과 관련된 모든 항목 (예 : waiter 개체)을 삭제하는 것입니다. 또는 작업을 인터럽트 할 수 있기를 원하기 때문에 으로 전화를 제거하여 SendAsyncCancel() 메서드를 사용하여 해결되지 않은 작업을 중단 할 수 있습니다.

(이 코드 예제에서는 주소를 ping으로 가져 오는 위치를 포함하여 전체 컨텍스트를 표시하지 않음) 시나리오에서 정확히 무엇이 잘못되었는지를 아는 것은 어렵습니다.

  1. 당신은 루프의 각 반복에서 Ping.Dispose() 방법을 요구하고있다 :하지만 난 당신이 게시 한 코드에 대한 관찰의 몇 가지를 제공 할 수 있습니다. 이것은 성공할 것으로 예상되는 루프의 첫 번째 반복에서만 의미합니다. 다음 반복에서는 ObjectDisposedException을 가져와 작업을 종료해야합니다.
  2. Ping.SendAsync()으로 진행중인 통화를 취소하려면 Ping.SendAsyncCancel() 메서드를 호출해야합니다. 이렇게하면 현재 ping 작업이 취소 상태로 완료됩니다. 물론 이것을 수행하려면 pingSender 참조를 양식의 코드에 어떻게 든 노출해야하므로 button2_Click() 메서드에 액세스 할 수 있습니다.
+0

코드는 Ping .SendAsync, 다음 줄에 Ping.Send를 호출하면 InvalidOperationException이 설명됩니다. inputBox.Lines를 읽는 작업자 스레드가 스레드 간 예외 (UI 스레드로 마샬링하지 않음)를 발생시킵니다. 아마도 그것은 결국 또는 다른 기계에있을 것입니다. – groverboy

+0

아, 그걸 알아 채지 못했습니다. Groverboy에게 감사드립니다. 나는 내 대답을 고칠 것이다. –