【问题标题】:How can I make many pings asynchronously at the same time?如何同时异步进行多个 ping?
【发布时间】:2014-03-31 11:20:09
【问题描述】:

我似乎无法理解如何构造对 SendPingAsync 的异步调用。我想遍历一个 IP 地址列表并异步 ping 它们,然后再继续程序……现在,一次遍历所有这些地址需要很长时间。我早些时候问了一个关于它的问题,以为我能够弄清楚异步,但显然我错了。

private void button1_Click(object sender, EventArgs e)
{
    this.PingLoop();
    MessageBox.Show("hi"); //for testing

}

public async void PingLoop()
{
    Task<int> longRunningTask = PingAsync();

    int result = await longRunningTask;
    MessageBox.Show("async call is finished!"); 

    //eventually want to loop here but for now just want to understand how this works
}

private async Task<int> PingAsync()
{
    Ping pingSender = new Ping();
    string reply = pingSender.SendPingAsync("www.google.com", 2000).ToString();
    pingReplies.Add(reply); //what should i be awaiting here?? 
    return 1;
}

恐怕我只是不明白这里到底发生了什么……我应该什么时候返回任务?当我按原样运行时,我只会得到一个冻结的 UI 和一个 ping 错误。我在这里阅读了 MSDN 文档和大量问题,但我就是不明白。

【问题讨论】:

    标签: c# multithreading ping


    【解决方案1】:

    你在这里 pingSender.SendPingAsync("www.google.com", 2000).ToString(); 做的事情没有多大意义。

    您应该返回 pingSender.SendPingAsync("www.google.com", 2000)

    await Task.WhenAll(your all ping requests)

    【讨论】:

      【解决方案2】:

      您想要的是一次启动所有 ping:

      var pingTargetHosts = ...; //fill this in
      var pingTasks = pingTargetHosts.Select(
           host => new Ping().SendPingAsync(host, 2000)).ToList();
      

      现在 ping 正在运行。收集他们的结果:

      var pingResults = await Task.WhenAll(pingTasks);
      

      现在处理的并发阶段已经完成,您可以检查和处理结果。

      【讨论】:

      • 如果您只想在WhenAll 中使用ToList(),为什么还要在pingTasks 上使用它?
      • @ReedCopsey 习惯,以获得更可靠的副作用。我以后可能会再次枚举pingTasks
      【解决方案3】:

      你想做这样的事情:

      private async Task<List<PingReply>> PingAsync()
      {
          var tasks = theListOfIPs.Select(ip => new Ping().SendPingAsync(ip, 2000));
          var results = await Task.WhenAll(tasks);
      
          return results.ToList();
      }
      

      这将异步启动theListOfIPs 中的每个 IP 的一个请求,然后异步等待它们全部完成。然后它将返回回复列表。

      请注意,与将结果设置在字段中相比,返回结果几乎总是更好。如果您在异步操作完成之前使用字段 (pingReplies),后者可能会导致错误 - 通过在使用 await 进行调用后返回并将范围添加到您的集合中,您可以使代码更清晰并且不易出错。

      【讨论】:

      • 我必须将“ip => pingSender.SendPingAsync(ip, 2000)”修改为 ip => new Ping().SendPingAsync(ip, 2000) 否则它会抛出“System.InvalidOperationException: An异步调用已在进行中,必须完成或取消后才能调用此方法"
      • 什么是 IP 列表?
      • @softwareisfun IP 列表
      【解决方案4】:

      这是我的做法

      private delegate void scanTargetDelegate(IPAddress ipaddress);
      
      private Task<PingReply> pingAsync(IPAddress ipaddress)
          {
              var tcs = new TaskCompletionSource<PingReply>();
              try
              {
      
                  AutoResetEvent are = new AutoResetEvent(false);
      
                  Ping ping = new Ping();
                  ping.PingCompleted += (obj, sender) =>
                      {
                          tcs.SetResult(sender.Reply);
                      };
                  ping.SendAsync(ipaddress, new object { });
      
              }
              catch (Exception)
              {
              }
              return tcs.Task;
          }
      

      在 BackgroundWorker 我这样做

      List<Task<PingReply>> pingTasks = new List<Task<PingReply>>();
      
              addStatus("Scanning Network");
              foreach (var ip in range)
              {
                  pingTasks.Add(pingAsync(ip));
              }
      
              Task.WaitAll(pingTasks.ToArray());
      
              addStatus("Network Scan Complete");
      
              scanTargetDelegate d = null;
              IAsyncResult r = null;
      
      foreach (var pingTask in pingTasks)
              {
                  if (pingTask.Result.Status.Equals(IPStatus.Success))
                  {
                      d = new scanTargetDelegate(scanTarget); //do something with the ip
                      r = d.BeginInvoke(pingTask.Result.Address, null, null);
                      Interlocked.Increment(ref Global.queuedThreads);
                  }
                  else
                  {
                      if (!ownIPs.Contains(pingTask.Result.Address))
                      {
                          failed.Add(pingTask.Result.Address);
                      }
                  }
              }
      
              if (r != null)
              {
                  WaitHandle[] waits = new WaitHandle[] { r.AsyncWaitHandle };
                  WaitHandle.WaitAll(waits);
              }
      

      【讨论】:

      【解决方案5】:
      public static async Task<bool> PingAsync(string host)
      {
          try
          {
              var ping = new System.Net.NetworkInformation.Ping();
              var reply = await ping.SendTaskAsync(host);
      
              return (reply.Status == System.Net.NetworkInformation.IPStatus.Success);
          }
          catch { return false; }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-22
        • 1970-01-01
        • 2021-12-12
        • 2012-05-11
        相关资源
        最近更新 更多