我尝试使用Ping.SendAsync()方法在C#中ping一些IP地址。我有一个带有5个IP地址的treeView,并为每个节点使用SendAsync()方法。在这里你可以看到:
private void Form1_Load(object sender, EventArgs e)
{
byte[] buffer = Encoding.ASCII.GetBytes(".");
PingOptions options = new PingOptions(50, true);
AutoResetEvent reset = new AutoResetEvent(false);
Ping ping = new Ping();
ping.PingCompleted += new PingCompletedEventHandler(ping_Complete);
foreach (TreeNode node in treeView1.Nodes)
{
ping.SendAsync(node.Text, 5000, buffer, options, reset);
}
}
private void ping_Complete(object sender, PingCompletedEventArgs k)
{
foreach (TreeNode node in treeView1.Nodes)
{
PingReply reply = k.Reply;
if (reply.Status == IPStatus.Success)
{
node.Text = node.Text + " (OK)";
}
else
{
node.Text = node.Text + " (FAILED)";
}
}
}
问题是,ping总是成功的。我有两个在线和pingable的客户端。其他3个脱机且不可ping(在cmd中我无法ping这些客户端)。所以它应该显示:
IP1 (OK)
IP2 (FAILED)
IP3 (FAILED)
IP4 (OK)
IP5 (FAILED)
但输出是“(OK)”的5倍。
有什么建议吗? :)
答案 0 :(得分:12)
我认为Jon对您的问题有正确的解释。
我的建议是你使用SendPingAsync
方法;它返回一个Task<PingReply>
你可以等待(你还需要使你的方法异步):
private async void Form1_Load(object sender, EventArgs e)
{
byte[] buffer = Encoding.ASCII.GetBytes(".");
PingOptions options = new PingOptions(50, true);
AutoResetEvent reset = new AutoResetEvent(false);
Ping ping = new Ping();
ping.PingCompleted += new PingCompletedEventHandler(ping_Complete);
foreach (TreeNode node in treeView1.Nodes)
{
var reply = await ping.SendPingAsync(node.Text, 5000, buffer, options, reset);
if (reply.Status == IPStatus.Success)
{
node.Text = node.Text + " (OK)";
}
else
{
node.Text = node.Text + " (FAILED)";
}
}
}
(请注意,此方法需要.NET 4.5)
正如mike z在评论中指出的那样,上面的方法将连续执行ping,而不是并行执行。如果你想并行完成它们,你可以这样做:
private async void Form1_Load(object sender, EventArgs e)
{
byte[] buffer = Encoding.ASCII.GetBytes(".");
PingOptions options = new PingOptions(50, true);
AutoResetEvent reset = new AutoResetEvent(false);
Ping ping = new Ping();
ping.PingCompleted += new PingCompletedEventHandler(ping_Complete);
var tasks = List<Task>();
foreach (TreeNode node in treeView1.Nodes)
{
var task = PingAndUpdateNodeAsync(ping, node);
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
private async Task PingAndUpdateNodeAsync(Ping ping, TreeNode node)
{
var reply = await ping.SendPingAsync(node.Text, 5000, buffer, options, reset);
if (reply.Status == IPStatus.Success)
{
node.Text = node.Text + " (OK)";
}
else
{
node.Text = node.Text + " (FAILED)";
}
}
答案 1 :(得分:8)
每次任何 PingCompleted
事件时,您都会以相同的方式更新所有树中的节点。相反,您应该只更新与特定PingCompletedEventArgs
对应的IP地址对应的节点。您可能希望将节点本身用作SendAsync
调用中的“状态”参数,以便您可以在事件处理程序中使用它。
我的猜测是,您要么失败,要么通过成功更新所有内容,或者您没有等待足够长的时间来查看失败。
为了验证这在诊断上是否正确,我建议你单独将reply.Status
记录在一个不会被覆盖的地方。
此外,您当前正在从非UI线程更新UI,这是一个非常糟糕的主意。在更新之前,您应该编组回UI线程。
答案 2 :(得分:1)
修复代码:
private void ping_Complete(object sender, PingCompletedEventArgs k)
{
foreach (TreeNode node in treeView1.Nodes)
{
PingReply reply = k.Reply;
if(reply.Address.ToString()==node.Text)
{
if (reply.Status == IPStatus.Success)
{
node.Text = node.Text + " (OK)";
}
else
{
node.Text = node.Text + " (FAILED)";
}
}
}
}