首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ping.SendAsync()始终成功,即使在cmd中无法even通客户端

问Ping.SendAsync()始终成功,即使在cmd中无法even通客户端
EN

Stack Overflow用户
提问于 2014-06-11 17:05:53
回答 3查看 9.1K关注 0票数 6

我尝试使用Ping.SendAsync()方法对C#中的一些IP地址执行ping操作。我有一个具有5个IP地址的treeView,并对每个节点使用SendAsync()方法。在这里您可以看到:

代码语言:javascript
复制
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通这些客户端)。因此,它应该显示以下内容:

代码语言:javascript
复制
IP1 (OK)
IP2 (FAILED)
IP3 (FAILED)
IP4 (OK)
IP5 (FAILED)

但是输出是"(OK)“的5倍。

有什么建议吗?:)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-06-11 17:09:50

我想Jon对你的问题有正确的解释。

我的建议是使用SendPingAsync方法;它返回一个您可以等待的Task<PingReply> (您还需要使您的方法异步):

代码语言:javascript
复制
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,而不是并行执行。如果你想并行地做这两件事,你可以这样做:

代码语言:javascript
复制
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)";
    }
}
票数 13
EN

Stack Overflow用户

发布于 2014-06-11 17:10:56

每当您获得任何PingCompleted事件时,您都会以相同的方式更新树中的所有节点。相反,您应该只更新与特定PingCompletedEventArgs对应的IP地址对应的节点。您可能希望将节点本身用作SendAsync调用中的“状态”参数,以便可以在事件处理程序中使用它。

我的猜测是,你要么失败了,然后用成功更新了一切,要么你没有等待足够长的时间来看到失败。

为了验证这是诊断正确的,我建议您将reply.Status单独记录到不会被覆盖的地方。

此外,您当前正在从非UI线程更新UI,这是一个非常糟糕的想法。在更新UI线程之前,应该将其封送回UI线程。

票数 8
EN

Stack Overflow用户

发布于 2014-06-11 17:17:37

修复代码:

代码语言:javascript
复制
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)";
           }
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24158814

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档