美好的一天。请帮帮我如何在这里停止 SendPingAsync 方法,我尝试了 SendAsyncCancel,但它只停止一个线程,我需要取消所有 pong 线程。
private void refreshbtn_Click(object sender, EventArgs e)
{
if (tokenSource != null) //check if its even initialized or not
tokenSource.Cancel();
lstNetworks.Items.Clear();
string gate_ip = NetworkGateway();
//Extracting and pinging all other ip's.
string[] array = gate_ip.Split('.');
for (int i = 1; i <= 255; i++)
{
string ping_var = array[0] + "." + array[1] + "." + array[2] + "." + i;
//time in milliseconds
Ping(ping_var, 1, 4000);
}
}
public void Ping(string host, int attempts, int timeout)
{
tokenSource = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);
ping.SendAsync(host, timeout, host);
}
catch
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}, tokenSource.Token);
}
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
// If an error occurred, display the exception to the user.
if (e.Reply.Status == IPStatus.Success)
{
string hostName = GetHostName(e.Reply.Address.ToString());
string macAdress = GetMacAddress(e.Reply.Address.ToString());
if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(new Action(() =>
{
lstNetworks.Items.Add(new InfoItem() { IP = e.Reply.Address.ToString(), MAC = macAdress, HOST = hostName });
lstNetworks.Items.SortDescriptions.Add(new SortDescription("IP", ListSortDirection.Ascending));
}));
}
}
else {
//Console.WriteLine(String.Concat("Non-active IP: ", e.Reply.Address.ToString()))
}
}
每次我单击刷新按钮时,我都应该开始新的ping操作。就我而言,只停止一个ping线程,但其余的继续工作。
更新
我尝试像你写的那样,当我再次按下刷新按钮时,我的应用程序冻结,直到所有线程停止(30 秒)。但是当应用程序解冻时,结果相同,我之前发送异步的所有ping数据包都会添加我第二次发送的新SensAsync数据包。我不仅需要停止线程,还需要停止 SendAsync 线程。有一个方法SendAsyncCancel,但是当取消令牌触发时,我如何在同时调用它。
您每次都会创建TokenSource
的不同实例。相反,只创建一个,将相同的实例传递到所有Tasks
。然后,每个Task
都会检查Token
是否有取消请求,然后您可以对每个请求进行 WaitAll,并将Token
传递到其中。
private async void refreshbtn_Click(object sender, EventArgs e)
{
if (tokenSource != null) //check if its even initialized or not
tokenSource.Cancel();
lstNetworks.Items.Clear();
string gate_ip = NetworkGateway();
//Extracting and pinging all other ip's.
tokenSource = new CancellationTokenSource();
string[] array = gate_ip.Split('.');
List<Task> tasks = new List<Task>();
for (int i = 1; i <= 255; i++)
{
string ping_var = array[0] + "." + array[1] + "." + array[2] + "." + i;
var task = Task.Factory.StartNew(() =>
{
if (tokenSource.Token.IsCancellationRequested) return;
//time in milliseconds
Ping(ping_var, 1, 4000, tokenSource.Token);
}, tokenSource.Token);
tasks.Add(task);
}
await Task.WhenAll(tasks.ToArray());
}
public void Ping(string host, int attempts, int timeout, CancellationToken cancellationToken)
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
cancellationToken.Register(() => ping.SendAsyncCancel());
ping.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);
ping.SendAsync(host, timeout, host);
}
catch
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}
更新:
添加了异步/等待,因此它不会阻止 UI。每个 Ping 的注册取消令牌,以便它可以自行取消。