Ping.SendAsyncCancel挂起任务

4
我正在使用Ping类定期ping几台主机。 如果下一次ping的时间到了,但是之前的ping尚未完成,我会调用SendAsyncCancel来终止它。
问题出现在如果我禁用网络接口,这种情况下异步回调将永远不会被调用,并且对SendAsyncCancel的调用也永远不会返回。
更多信息如下:我正在使用.NET 3.5和C# VS2008 express在Windows 7 x64上进行开发。 我从窗体的Timer.Tick回调中调用ping。 我仅为每个主机创建一次Ping类(总共3个主机,但只有一个主机时相同)。 超时设置为5秒。 该问题可以100%重现。
我发现的所有问题都与ping崩溃在多次创建/销毁ping类时有关,但这并不是我的情况。
using System;
using System.Net.NetworkInformation;
using System.Windows.Forms;

    namespace TestPing {
      public partial class Form1 : Form {

        private Ping Pinger;

         public Form1()
         {
           InitializeComponent();
           Pinger = new Ping();
           Pinger.PingCompleted += new PingCompletedEventHandler(PingCompletedCallback);
         }

        private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
        {
          txtResult.Text = e.Cancelled ? "Cancelled" : e.Reply.Status.ToString();
        }

        private void butSend_Click(object sender, EventArgs e)
        {
          txtResult.Text = "(result)";
          txtStatus.Text = "SendAsync() calling...";
          Pinger.SendAsync(txtHost.Text, null);
          txtStatus.Text = "SendAsync() done.";
        }

        private void butCancel_Click(object sender, EventArgs e)
        {
          txtStatus.Text = "SendAsyncCancel() calling...";
          Pinger.SendAsyncCancel();
          txtStatus.Text = "SendAsyncCancel() done.";
        }
      }
    }

你能否将相同的示例代码或精确的代码提取到单独的测试应用程序中,以便我们进行调查? - Yura
我创建了一个空项目来复现并发布其代码。同时我注意到,如果我在ping不存在的主机(但网络已连接)时使用SendAsyncCancel,则只有在ping超时期过后才会取消,而不是立即取消。因此,问题的根源可能是在取消之前等待完成。 - G-Shadow
https://msdn.microsoft.com/en-us/library/ms144962(v=vs.110).aspx - Igor Gorjanc
1个回答

1
Pinger.SendAsyncCancel()似乎并不真正异步执行。在使用.NET 3.5时,您可以执行以下操作:
private void butSend_Click(object sender, EventArgs e)
{
    txtStatus.Text = "Pinging";
    Pinger.SendAsync(txtHost, null);
}

private void butCancel_Click(object sender, EventArgs e)
{
    Thread t = new Thread(Pinger.SendAsyncCancel);
    t.Start();
}

现在,你的 txtStatus.Text = "Cancel done"; 将会放在这里:
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
  if(e.Cancelled)
  {
     txtResult.Text = "Cancelled";
     txtStatus.Text = "Cancel done";
  }
  else
  {
     txtResult.Text = e.Reply.Status.ToString();
     txtStatus.Text = "SendAsync done";
  }
}

这在我的端上运作得像我期望的一样。

谢谢,但这并没有解决原来的问题。现在程序界面不再挂起,因为单独的线程挂起了。SendAsyncCancel从未完成,Pinger类变得无法使用(操作仍在等待),程序永远不会退出,因为该线程一直等待。我想知道为什么ping会永远等待,如果没有网络连接,这是奇怪的行为。 - G-Shadow
在我的测试中,文本框在我点击取消按钮几秒钟后显示了“已取消”。这是期望的结果,对吧?稍后会全部发布。 - Chris Wohlert
@G-Shadow,请看一下,看看你的代码是否与我的匹配。 - Chris Wohlert
我尝试了你的代码,但问题仍然存在。你试过断开网络电缆(或禁用连接)吗? - G-Shadow
@G-Shadow,是的,插上电缆后,它会立即显示成功。 - Chris Wohlert
这帮助了我在WPF中。 - Alexander Yashyn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接