2014-02-27 137 views
6

我似乎无法理解如何构建对SendPingAsync的异步调用。我想循环访问IP地址列表,并在程序中继续进行所有的异步ping命令......现在,需要永久地逐个查看所有的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文档和大量的问题,我只是没有得到它。

回答

8

你想要做这样的事情:

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

    return results.ToList(); 
} 

这将在theListOfIPs开始每个IP一个异步请求,然后异步等待他们全部完成。它会返回回复列表。

请注意,返回结果与将它们设置在字段中几乎总是更好。后者可能会导致错误,如果你去完成异步操作之前,使用的字段(pingReplies) - 通过返回,并添加至您的收藏该呼叫与await后,您使代码更清晰和更少的错误容易。

+4

我不得不修改ip => pingSender.SendPingAsync(ip,2000)“ip => new Ping()。SendPingAsync(ip,2000)否则会抛出”System.InvalidOperationException:异步调用已在进行中。必须完成或取消之后才能调用此方法“ – pingo

+0

什么是ListOfIP? –

+0

@softwareisfun IP列表。 –

2

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

相反,你应该返回pingSender.SendPingAsync("www.google.com", 2000)

await Task.WhenAll(your all ping requests)

1

你需要的是立即启动所有坪:

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

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

var pingResults = await Task.WhenAll(pingTasks); 

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

+0

为什么'ToList()'在pingTasks如果你只是要与WhenAll反正使用它呢? –

+0

@ReedCopsey习惯,以获得更可靠的副作用。我可能以后再次枚举'pingTasks'。 – usr

0

这里是我如何做到这一点

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); 
     } 
+2

你不需要那样做--'''已经支持异步:http://msdn.microsoft.com/en-us/library/hh193994(v=vs.110).aspx –

+0

好吧,它使它更容易 – Tsukasa