【发布时间】:2015-01-20 01:31:55
【问题描述】:
我正在开发这个程序以同时 ping 大量 IP 地址,我尝试一次简单地 ping 每个地址,但是一旦我开始 ping 50 多个主机,它就会变得非常长。我遇到的问题是,当我尝试 ping 超过 1 个主机时,我无法在单击取消按钮时停止异步线程并收到此错误。我花了 2 天时间试图弄明白,但没有运气。具体错误如下:
System.InvalidOperationException:异步调用已经在 进步。必须先完成或取消,然后才能调用此方法。 在 System.Net.NetworkInformation.Ping.CheckStart(布尔异步) 在 System.Net.NetworkInformation.Ping.Send(IPAddress 地址,Int32 超时,字节 [] 缓冲区,PingOptions 选项) 在 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);
}
}
}
}
【问题讨论】:
-
不阅读代码..您可能可以将取消令牌传递给异步方法。
-
与论坛网站不同,我们不使用“谢谢”、“任何帮助表示赞赏”或Stack Overflow 上的签名。请参阅“Should 'Hi', 'thanks,' taglines, and salutations be removed from posts?.
-
如果你调用
Invoke,你需要从回调中调用EndInvoke,这会结束调用。 -
@Mgetz:您正在考虑关于
BeginInvoke()的规则,而不是Invoke()。它不适用于这里。请注意,虽然按照惯例应该匹配一对BeginXXX()和EndXXX()方法,但在Control.BeginInvoke()和编译器生成的委托类型的BeginInvoke()方法的情况下,Microsoft 多年来一直提供以下指导:在这些情况下,无需致电EndInvoke()(即它们是规则的例外)。
标签: c# asynchronous ping