TraceRoute und Ping in C#

TraceRoute und Ping in C#

Angesichts der Tatsache, dass ich heute eine TraceRoute-Klasse schreiben musste, dachte ich, ich könnte den Quellcode genauso gut teilen.

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;
    }
  }
}

Und eine VB-Version für jeden, der sie will/braucht

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

Was folgt, ist eine deutlich bessere C#-Implementierung von tracert als bisher in anderen Antworten existiert.

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

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

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

            // we've found a route at this ttl
            if (reply.Status == IPStatus.Success || reply.Status == IPStatus.TtlExpired)
                yield return reply.Address;

            // if we reach a status other than expired or timed out, we're done searching or there has been an error
            if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.TimedOut)
                break;
        }
    }
}

Zu den hier behobenen Fallstricken, die in anderen Antworten vorhanden sind, gehören:

  • Es ist faul. Beispiel:Es verwendet enumerable / einen Iterator, sodass Sie nicht den gesamten Baum berechnen müssen. Sie können an jedem Punkt aufhören, indem Sie aus Ihrer eigenen verbrauchenden Schleife ausbrechen.
  • maxTTL implementiert, damit die Funktion nicht ewig weiterläuft.
  • bufferSize Option, die mit anderen Tracert-Implementierungen konsistent ist.
  • Es ist super prägnant und sauber. Es ist in einer einzigen Methode enthalten und wesentlich kürzer als andere Optionen hier.

Obwohl die Basisklassenbibliothek Ping enthält, enthält die BCL keine Tracert-Funktionalität.

Eine schnelle Suche zeigt jedoch zwei Open-Source-Versuche, den ersten in C#, den zweiten in C++:

  • http://www.codeproject.com/KB/IP/tracert.aspx
  • http://www.codeguru.com/Cpp/I-N/network/basicnetworkoperations/article.php/c5457/