TraceRoute et Ping en C#

est-ce que quelqu'un a le code C sous la main pour faire un ping et traceroute à un ordinateur cible? Je cherche une solution de code pur, pas ce que je fais en ce moment, qui est d'invoquer le ping.exe et tracert.exe programme et l'analyse de la sortie. Je voudrais quelque chose de plus robuste.

28
demandé sur Stephen Kennedy 2008-09-27 04:29:23

6 réponses

bien que la bibliothèque de classe de Base inclue Ping , la BCL n'inclut aucune fonctionnalité de tracert.

Toutefois, une recherche rapide révèle deux open-source tentatives, la première en C# le deuxième en C++:

13
répondu Portman 2008-09-27 02:46:38

Etant donné que j'ai dû écrire une classe TraceRoute aujourd'hui, j'ai pensé que je pourrais aussi bien partager le code source.

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

et une version VB pour tous ceux qui le veulent/en ont besoin

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
55
répondu Scott 2014-10-31 09:13:34

pour la partie ping, jetez un oeil à la Classe Ping sur MSDN.

7
répondu Bruno Gomes 2008-09-27 00:33:50

ce qui suit est une meilleure mise en œuvre de tracert que ce qui existe dans les autres réponses jusqu'à présent.

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

les pièges corrigés ici qui sont présents dans d'autres réponses comprennent:

  • c'est paresseux. Ex: il utilise correctement énumerable / un iterator afin de ne pas avoir à calculer l'arbre entier, vous pouvez arrêter à tout moment en sortant de votre propre boucle de consommation.
  • maxTTL mise en œuvre la fonction ne tourne pas pour toujours.
  • bufferSize option compatible avec d'autres implémentations de tracert.
  • c'est super concis et propre. Il est contenu dans une méthode simple et est considérablement plus court que d'autres options ici.
7
répondu caesay 2018-10-03 15:01:57

comme am amélioration à Scotts Code réponse ci - dessus, j'ai constaté que sa solution ne fonctionne pas si la route s'amenuise dans rien avant d'atteindre la destination-il ne retourne jamais. Une meilleure solution avec au moins une route partielle pourrait être celle-ci (que j'ai testé et qui fonctionne bien). Vous pouvez changer le '20' dans la boucle for en quelque chose de plus grand ou plus petit ou essayer de détecter si cela prend trop de temps si vous voulez contrôler le nombre d'itérations d'une autre manière. Crédit à Scott pour le code d'origine-merci.

    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;
        }
    }
0
répondu Nigel Thomas 2017-03-08 23:13:49

Ping : nous pouvons utiliser la classe Ping intégrée dans le cadre.net.

Instancier Ping et de vous abonner à la PingCompleted de l'événement:

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

ajouter du code pour configurer et activer le ping, par exemple:

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

Ajouter un PingCompletedEventHandler :

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

Code-dump d'un exemple de fonctionnement complet, basé sur exemple de MSDN :

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();
}
0
répondu Stephen Kennedy 2018-03-12 13:50:45