在Mono下C#Ping延迟/慢

时间:2015-03-17 08:08:31

标签: c# .net mono ping

我在使用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. Pre ping:03/17/2015 15:43:21
  2. Post ping:03/17/2015 15:43:41
  3. 成功! RTT:2
  4. Pre ping:03/17/2015 15:43:41
  5. Post ping:03/17/2015 15:44:01
  6. 成功! RTT:46
  7. 你可以看到" Pre"和"发布"时间戳,有20秒的延迟(这是一致的,它总是20秒)。运行Mono的机器在同一个172.16.1。*网络上,我把Google ping放在那里进行额外的测试。

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

    1. Pre ping:17/03/2015 3:38:21 PM
    2. Post ping:17/03/2015 3:38:21 PM
    3. 成功! RTT:3
    4. Pre ping:17/03/2015 3:38:21 PM
    5. Post ping:17/03/2015 3:38:21 PM
    6. 成功! RTT:46
    7. 关于这里发生了什么的任何想法?我需要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秒。但仍然不理想。

1 个答案:

答案 0 :(得分:1)

这种方式取决于权限的设置方式。

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

您可能想要检查的第一件事是实际发生的事情。在您尝试执行ping操作时ping是否会执行?如果您sudo申请,会有帮助吗?

默认超时是4秒,因此它不应该永远需要20秒 - 你应该在此之前很久就有一个超时。并且您明确地传递了60毫秒的超时。

所有这些(以及对Mono中代码处理ping的好看)表明其中一个:

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

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

除了发送请求并等待回复之外,您真的希望使用异步套接字来一直发送和接收,直到您通过所有要ping的主机,同时检查您所做的那些主机。及时得到回复。