TraceRoute y Ping en C#
.net networking (6)
A medida que supero la respuesta del código de Scotts anterior, descubrí que su solución no funciona si la ruta se reduce a cero antes de llegar al destino, nunca regresa. Una mejor solución con al menos una ruta parcial podría ser esta (que he probado y funciona bien). Puede cambiar el ''20'' en el bucle for a algo más grande o más pequeño o tratar de detectar si tarda demasiado si desea controlar el número de iteraciones de otra manera. Todo el crédito a Scott por el código original - gracias.
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;
}
}
¿Alguien tiene código de C # a mano para hacer un ping y traceroute a una computadora de destino? Estoy buscando una solución de código puro, no lo que estoy haciendo ahora, que invoca el programa ping.exe y tracert.exe y analiza el resultado. Me gustaría algo más robusto.
Aunque la Biblioteca de clases base incluye Ping , el BCL no incluye ninguna funcionalidad de tracert.
Sin embargo, una búsqueda rápida revela dos intentos de código abierto, el primero en C # y el segundo en C ++:
Dado que hoy tuve que escribir una clase TraceRoute, pensé que también podría compartir el código fuente.
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;
}
}
}
Y una versión VB para cualquiera que lo quiera / lo necesite
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
Lo que sigue es una implementación de tracert
significativamente mejor que la que existe en otras respuestas hasta el momento.
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.Success)
{
// Success means the tracert has completed
yield return reply.Address;
break;
}
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 we reach here, it''s a status we don''t recognize and we should exit.
break;
}
}
Las trampas corregidas aquí que están presentes en otras respuestas incluyen:
- Es flojo. Por ejemplo, utiliza correctamente un enumerable / iterador, por lo que no tiene que calcular todo el árbol, puede detenerse en cualquier punto saliendo de su propio ciclo de consumo.
-
maxTTL
implementado para que la función no semaxTTL
para siempre. -
bufferSize
opciónbufferSize
que es consistente con otras implementaciones de tracert. - Es súper conciso y limpio. Está contenido en un solo método y es considerablemente más corto que otras opciones aquí.
Para la parte de ping, eche un vistazo a la Ping en MSDN.
Ping : Podemos usar la clase Ping
integrada en .NET Framework.
Crea una instancia de un Ping
y suscríbete al evento PingCompleted
:
Ping pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
Agregue código para configurar y haga ping, por ejemplo:
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);
Agregue PingCompletedEventHandler
:
public static void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
... Do stuff here
}
Volcado de código de un ejemplo de trabajo completo, basado en el ejemplo 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();
}