通过按钮单击WPF停止Ping.SendAsync

时间:2016-04-22 15:00:33

标签: c# wpf multithreading ping

美好的一天。请帮助我,我怎么能在这里停止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,但是如何在取消令牌触发时同时调用它。?

1 个答案:

答案 0 :(得分:1)

您每次都在创建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.
    }
}

<强>更新

添加了async / await,因此它不会阻止UI。为每个Ping注册取消令牌,以便它可以自行取消。