【问题标题】:C# Ping delay/slow under MonoMono下的C# Ping延迟/慢
【发布时间】:2015-05-19 14:00:17
【问题描述】:

我在 Mono 3.2.8 下运行的 C# .Net 4.5 中遇到了 Ping.Send 延迟问题。我的代码如下所示:

using(var sw = new StreamWriter("/ping.txt"))
{
    var ping = new Ping();
    PingReply reply;

    sw.WriteLine("Pre ping: {0}", DateTime.Now);
    // Ping local machine
    reply = ping.Send("172.16.1.100", 60);
    sw.WriteLine("Post ping: {0}", DateTime.Now);

    if (reply != null && reply.Status == IPStatus.Success)
    {
        sw.WriteLine("Success! RTT: {0}", reply.RoundtripTime);
    }

    sw.WriteLine("Pre ping: {0}", DateTime.Now);
    // Ping Google
    reply = ping.Send("216.58.220.110", 60);
    sw.WriteLine("Post ping: {0}", DateTime.Now);

    if (reply != null && reply.Status == IPStatus.Success)
    {
        sw.WriteLine("Success! RTT: {0}", reply.RoundtripTime);
    }
}

在 Linux 上的 Mono 下运行上述代码的输出是:

  1. 预ping:03/17/2015 15:43:21
  2. 发布 ping:03/17/2015 15:43:41
  3. 成功! RTT:2
  4. 预ping:03/17/2015 15:43:41
  5. 发布 ping:03/17/2015 15:44:01
  6. 成功! RTT:46

您可以看到,在“Pre”和“Post”时间戳之间,有 20 秒的延迟(这是一致的,始终是 20 秒)。运行 Mono 的机器在同一个 172.16.1.* 网络上,我将 Google ping 放在那里进行额外测试。

在我的 Windows 机器上本地运行相同的代码会产生以下输出(ping 没有延迟):

  1. 预 ping:2015 年 3 月 17 日下午 3:38:21
  2. 发布 ping:2015 年 3 月 17 日下午 3:38:21
  3. 成功! RTT:3
  4. 预 ping:2015 年 3 月 17 日下午 3:38:21
  5. 发布 ping:2015 年 3 月 17 日下午 3:38:21
  6. 成功! RTT:46

关于这里发生了什么的任何想法?我需要 ping 数百台机器,因此 ping 之间 20 秒的延迟是不可接受的。

更新: 我试过使用Ping.SendAsync 方法和下面的代码:

private void PingAsyncTest()
{
    var ipAddresses = new List<String> { "172.16.1.100", "216.58.220.110" };

    foreach (var ipAddress in ipAddresses)
    {
        using (var ping = new Ping())
        {
            ping.PingCompleted += PingCompleted;
            ping.SendAsync(IPAddress.Parse(ipAddress), 1000);
        }
    }
}

private void PingCompleted(object sender, PingCompletedEventArgs e)
{
    if (e.Reply.Status == IPStatus.Success)
    {
        // Update successful ping in the DB.
    }
}

我仍然看到SendAsync 呼叫和回复到达PingCompleted 之间的 20 秒延迟。这比应用程序在发送下一个 ping 之前等待 20 秒的原始代码要好一些。这样,所有 ping 都是异步发送和接收的,因此每次 ping 无需等待 20 秒。不过还是不太理想。

【问题讨论】:

  • 可以肯定的是,从 Linux 机器执行简单的命令行 ping 具有足够的性能?你能启动像 Wireshark 这样的工具来查看网络级别发生了什么吗?

标签: c# .net mono ping


【解决方案1】:

这在很大程度上取决于权限的设置方式。

如果您的应用程序获得足够的权限,它将直接尝试发送 ICMP 请求。另一方面,如果不允许发送 ICMP,它将运行ping 可执行文件(试图在/bin/ping/sbin/ping/usr/sbin/ping 中找到它)。

您可能要检查的第一件事是哪些实际发生了。 ping 在您尝试执行 ping 操作时是否执行?如果您sudo您的应用程序有帮助吗?

默认超时时间为 4 秒,因此它不应该永远花费 20 秒 - 您应该在此之前很久就获得超时。而且您明确传递了 60 毫秒的超时时间。

所有这些(以及对 Mono 中代码处理 ping 的深入了解)都表明了其中之一:

  • Ping 类本身的初始设置需要 20 秒 - 查询功能、查找 ping 等。显然情况并非如此,因为您尝试了两次 ping 并且每个 ping长。
  • 大部分时间都花在实际 ICMP/ping 代码之外。最有可能的位置是 Dns.GetHostNameDns.GetHostAddresses。与 ping 本身分开检查。
  • 其他一些线程/进程正在干扰您自己的 ping。 ICMP 套接字将获得所有 ICMP 响应,因为在 ICMP 中没有端口等概念。

最后一点也暗示了另一个问题——如果你试图 ping 很多不同的主机,你真的不想使用Ping,至少在 Linux 上是这样。相反,您需要确保您的应用程序以特权方式运行(有足够的权限来执行原始 ICMP),并通过单个 Socket 处理所有 ICMP 请求和回复。如果您使用 Ping.Send 并行发送 100 个请求,则每个 Ping.Sends 都必须通过所有回复,而不仅仅是他们期望的回复。此外,使用 60 毫秒作为超时听起来不是一个好主意,因为代码使用 DateTime.Now 来检查超时,这可能具有非常低的超时分辨率。

您真的希望始终使用异步套接字来发送和接收,而不是发送请求并等待回复,直到您通过所有要 ping 的主机,同时检查您没有的主机'没有及时回复。

【讨论】:

  • 使用 DateTime.Now 只是为了显示运行 Ping.Send 命令需要多长时间。我真的只关心 ping 是否成功,在这种情况下,我会更新数据库中的一个字段来说明这一点。我曾考虑过异步执行 ping,我会对此进行尝试,看看我会得到什么结果。
  • @sfinks_29:我不是说你使用DateTime.Now——它实际上是在Mono的Ping.Send内部使用的。只需尝试使用像 5005000 这样的超时。
  • 我尝试将超时时间增加到 500 和 5000,没有变化。我还在应用程序运行时监控了进程列表,我根本看不到 ping 出现。
  • 我已经使用 Ping.SendAsync 的代码 sn-p 更新了我的原始问题。结果仍然不理想,但它解决了每个单独的 ping 必须等待 20 秒的问题。
猜你喜欢
  • 2012-03-27
  • 2010-10-20
  • 1970-01-01
  • 2018-09-19
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 2014-04-23
  • 2011-02-01
相关资源
最近更新 更多