我正在使用这个程序来同时ping大量的IP地址我尝试一次只ping一个地址但是一旦我开始ping 50多个主机它就变得非常长。我遇到的问题是,我无法在取消按钮单击时停止异步线程,并在尝试ping多个主机时出现此错误。我花了两天的时间试图搞清楚它并没有运气。确切的错误如下:
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 :(得分:0)
您的代码的直接问题(即异常原因)是您在循环中同时调用Ping.Send()
和Ping.SendAsync()
。拨打Ping.SendAsync()
后,对Send()
或SendAsync()
的任何后续调用都是非法的,直到第一次SendAsync()
操作完成为止。
目前尚不清楚为什么你们两个都有。鉴于您似乎想要同步进行调用,最简单的方法是简单地删除对SendAsync()
的调用以及与其相关的任何内容(即waiter
对象)。或者,由于您似乎希望能够中断操作,您可能更愿意删除对Send()
的调用,以便您可以使用SendAsyncCancel()
方法来中断未完成的操作。
缺少a good, complete code example(此代码示例未显示完整的上下文,包括您获取ping地址的位置),很难确切知道您的方案中出现了什么问题。但我可以提供一些关于你发布的代码的观察结果:
Ping.Dispose()
方法。这意味着只有在循环的第一次迭代中,您才能期望成功。在下一次迭代中,您应该获得ObjectDisposedException
,终止工作!Ping.SendAsync()
的正在进行的通话,则应调用Ping.SendAsyncCancel()
方法。这将导致当前ping操作以取消状态完成。当然,要做到这一点,您需要以某种方式公开对表单代码的pingSender
引用,以便button2_Click()
方法可以访问它。