C#中的TraceRoute和Ping

时间:2008-09-27 00:29:24

标签: c# .net networking ping traceroute

有没有人有C#代码方便ping和traceroute到目标计算机?我正在寻找一个纯代码解决方案,而不是我现在正在做的,它调用ping.exe和tracert.exe程序并解析输出。我想要更强大的东西。

7 个答案:

答案 0 :(得分:55)

鉴于我今天必须写一个TraceRoute类,我想我也可以分享源代码。

using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Text;
using System.Net;

namespace Answer
{  
  public class TraceRoute
  {
    private const string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    public static IEnumerable<IPAddress> GetTraceRoute(string hostNameOrAddress)
    {
      return GetTraceRoute(hostNameOrAddress, 1);
    }
    private static IEnumerable<IPAddress> GetTraceRoute(string hostNameOrAddress, int ttl)
    {
      Ping pinger = new Ping();
      PingOptions pingerOptions = new PingOptions(ttl, true);
      int timeout = 10000;
      byte[] buffer = Encoding.ASCII.GetBytes(Data);
      PingReply reply = default(PingReply);

      reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions);

      List<IPAddress> result = new List<IPAddress>();
      if (reply.Status == IPStatus.Success)
      {
        result.Add(reply.Address);
      }
      else if (reply.Status == IPStatus.TtlExpired || reply.Status == IPStatus.TimedOut)
      {
        //add the currently returned address if an address was found with this TTL
        if (reply.Status == IPStatus.TtlExpired) result.Add(reply.Address);
        //recurse to get the next address...
        IEnumerable<IPAddress> tempResult = default(IEnumerable<IPAddress>);
        tempResult = GetTraceRoute(hostNameOrAddress, ttl + 1);
        result.AddRange(tempResult);
      }
      else
      {
        //failure 
      }

      return result;
    }
  }
}

为任何想要/需要它的人提供VB版本

Public Class TraceRoute
    Private Const Data As String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

    Public Shared Function GetTraceRoute(ByVal hostNameOrAddress As String) As IEnumerable(Of IPAddress)
        Return GetTraceRoute(hostNameOrAddress, 1)
    End Function
    Private Shared Function GetTraceRoute(ByVal hostNameOrAddress As String, ByVal ttl As Integer) As IEnumerable(Of IPAddress)
        Dim pinger As Ping = New Ping
        Dim pingerOptions As PingOptions = New PingOptions(ttl, True)
        Dim timeout As Integer = 10000
        Dim buffer() As Byte = Encoding.ASCII.GetBytes(Data)
        Dim reply As PingReply

        reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions)

        Dim result As List(Of IPAddress) = New List(Of IPAddress)
        If reply.Status = IPStatus.Success Then
            result.Add(reply.Address)
        ElseIf reply.Status = IPStatus.TtlExpired Then
            'add the currently returned address
            result.Add(reply.Address)
            'recurse to get the next address...
            Dim tempResult As IEnumerable(Of IPAddress)
            tempResult = GetTraceRoute(hostNameOrAddress, ttl + 1)
            result.AddRange(tempResult)
        Else
            'failure 
        End If

        Return result
    End Function
End Class

答案 1 :(得分:13)

虽然基类库包含Ping,但BCL不包含任何tracert功能。

然而,快速搜索揭示了两个开源尝试,第一个在C#中是C ++中的第二个:

答案 2 :(得分:9)

以下是tracert的C#实现比迄今为止其他答案中存在的明显更好。

public static IEnumerable<IPAddress> GetTraceRoute(string hostname)
{
    // following are the defaults for the "traceroute" command in unix.
    const int timeout = 10000;
    const int maxTTL = 30;
    const int bufferSize = 32;

    byte[] buffer = new byte[bufferSize];
    new Random().NextBytes(buffer);
    Ping pinger = new Ping();

    for (int ttl = 1; ttl <= maxTTL; ttl++)
    {
        PingOptions options = new PingOptions(ttl, true);
        PingReply reply = pinger.Send(hostname, timeout, buffer, options);

        if (reply.Status == IPStatus.TtlExpired)
        {
            // TtlExpired means we've found an address, but there are more addresses
            yield return reply.Address;
            continue;
        }
        if (reply.Status == IPStatus.TimedOut)
        {
            // TimedOut means this ttl is no good, we should continue searching
            continue;
        }
        if (reply.Status == IPStatus.Success)
        {
            // Success means the tracert has completed
            yield return reply.Address;
        }

        // if we ever reach here, we're finished, so break
        break;
    }
}

其他答案中出现的陷阱包括:

  • 很懒。例如:它正确使用了枚举/迭代器,所以不必计算整个树,你可以通过打破自己的消费循环来随时停止。
  • maxTTL已实施,因此该功能不会永远旋转。
  • bufferSize选项与其他tracert实现一致。
  • 它超级简洁干净。它包含在一个方法中,比这里的其他选项要短得多。

答案 3 :(得分:7)

对于ping部分,请查看MSDN上的Ping class

答案 4 :(得分:1)

这是我能想到的最有效的方法。 如果您喜欢,请投票,让其他人受益。

    using System;
    using System.Collections.Generic;
    using System.Net.NetworkInformation;

    namespace NetRouteAnalysis
    {
        class Program
        {
            static void Main(string[] args)
            {
                var route = TraceRoute.GetTraceRoute("8.8.8.8")

                foreach (var step in route)
                {
                    Console.WriteLine($"{step.Address,-20} {step.Status,-20} \t{step.RoundtripTime} ms");
                }
            }
        }

        public static class TraceRoute
        {
            public static IEnumerable<PingReply> GetTraceRoute(string hostnameOrIp)
            {
                // Initial variables
                var limit = 1000;
                var buffer = new byte[32];
                var pingOpts = new PingOptions(1, true);
                var ping = new Ping();               

                // Result holder.
                PingReply result = null;

                do
                {
                    result = ping.Send(hostnameOrIp, 4000, buffer, pingOpts);
                    pingOpts = new PingOptions(pingOpts.Ttl + 1, pingOpts.DontFragment);

                    if (result.Status != IPStatus.TimedOut)
                    {
                        yield return result;
                    }
                }
                while (result.Status != IPStatus.Success && pingOpts.Ttl < limit);
            }
        }       
    }

答案 5 :(得分:0)

由于对上述Scotts代码答案的改进,我发现如果路线在到达目的地之前逐渐减少为零,他的解决方案并不起作用 - 它永远不会返回。至少部分路线的更好的解决方案可能是这个(我已经测试过并且效果很好)。你可以改变&#39; 20&#39;在for循环中更大或更小的东西或尝试检测它是否需要花费太长时间,如果你想以其他方式控制迭代次数。斯科特完全赞同原始代码 - 谢谢。

    using System.Collections.Generic;
    using System.Net.NetworkInformation;
    using System.Text;
    using System.Net;

    ...

    public static void TraceRoute(string hostNameOrAddress)
    {
        for (int i = 1; i < 20; i++)
        {
            IPAddress ip = GetTraceRoute(hostNameOrAddress, i);
            if(ip == null)
            {
                break;
            }
            Console.WriteLine(ip.ToString());
        }
    }

    private static IPAddress GetTraceRoute(string hostNameOrAddress, int ttl)
    {
        const string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        Ping pinger = new Ping();
        PingOptions pingerOptions = new PingOptions(ttl, true);
        int timeout = 10000;
        byte[] buffer = Encoding.ASCII.GetBytes(Data);
        PingReply reply = default(PingReply);

        reply = pinger.Send(hostNameOrAddress, timeout, buffer, pingerOptions);

        List<IPAddress> result = new List<IPAddress>();
        if (reply.Status == IPStatus.Success || reply.Status == IPStatus.TtlExpired)
        {
            return reply.Address;
        }
        else
        {
            return null;
        }
    }

答案 6 :(得分:0)

Ping :我们可以使用.NET Framework中内置的Ping类。

实例化Ping并订阅PingCompleted事件:

Ping pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;

添加代码以配置和操作ping,例如:

string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
string who = "www.google.com";
AutoResetEvent waiter = new AutoResetEvent(false);
int timeout = 12000;

PingOptions options = new PingOptions(64, true);

pingSender.SendAsync(who, timeout, buffer, options, waiter);

添加PingCompletedEventHandler

public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
    ... Do stuff here
}

完整工作示例的代码转储,基于MSDN's example

public static void Main(string[] args)
{
    string who = "www.google.com";
    AutoResetEvent waiter = new AutoResetEvent(false);

    Ping pingSender = new Ping();

    // When the PingCompleted event is raised,
    // the PingCompletedCallback method is called.
    pingSender.PingCompleted += PingCompletedCallback;

    // Create a buffer of 32 bytes of data to be transmitted.
    string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    byte[] buffer = Encoding.ASCII.GetBytes(data);

    // Wait 12 seconds for a reply.
    int timeout = 12000;

    // Set options for transmission:
    // The data can go through 64 gateways or routers
    // before it is destroyed, and the data packet
    // cannot be fragmented.
    PingOptions options = new PingOptions(64, true);

    Console.WriteLine("Time to live: {0}", options.Ttl);
    Console.WriteLine("Don't fragment: {0}", options.DontFragment);

    // Send the ping asynchronously.
    // Use the waiter as the user token.
    // When the callback completes, it can wake up this thread.
    pingSender.SendAsync(who, timeout, buffer, options, waiter);

    // Prevent this example application from ending.
    // A real application should do something useful
    // when possible.
    waiter.WaitOne();
    Console.WriteLine("Ping example completed.");
}

public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
    // If the operation was canceled, display a message to the user.
    if (e.Cancelled)
    {
        Console.WriteLine("Ping canceled.");

        // Let the main thread resume. 
        // UserToken is the AutoResetEvent object that the main thread 
        // is waiting for.
        ((AutoResetEvent)e.UserState).Set();
    }

    // If an error occurred, display the exception to the user.
    if (e.Error != null)
    {
        Console.WriteLine("Ping failed:");
        Console.WriteLine(e.Error.ToString());

        // Let the main thread resume. 
        ((AutoResetEvent)e.UserState).Set();
    }

    Console.WriteLine($"Roundtrip Time: {e.Reply.RoundtripTime}");

    // Let the main thread resume.
    ((AutoResetEvent)e.UserState).Set();
}
相关问题