Есть ли у кого-нибудь удобный код C# для выполнения ping и traceroute на целевой компьютер? Я ищу решение на чистом коде, а не то, что я делаю сейчас, которое вызывает программы ping.exe и tracert.exe и анализирует вывод. Хотелось бы чего-нибудь более крепкого.





Что касается проверки связи, обратите внимание на Ping класс в MSDN.
Хотя библиотека базовых классов включает пинг, BCL не включает никаких функций tracert.
Однако при быстром поиске обнаруживаются две попытки с открытым исходным кодом, первая на C#, вторая на C++:
Учитывая, что сегодня мне нужно было написать класс 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
Классный раствор. Незначительный момент, но поскольку вы использовали возврат IEnumerable <>, вы можете подумать о возврате yield вместо заполнения списка.
Если кто-то наткнется на это, у него есть некоторые проблемы, в том числе то, что он может никогда не возвращаться и вращаться вечно. пожалуйста посмотрите stackoverflow.com/a/45565253/184746
В качестве улучшения приведенного выше ответа на код Скотта я обнаружил, что его решение не работает, если маршрут сужается до нуля до достижения пункта назначения - он никогда не возвращается. Лучшим решением может быть хотя бы частичный маршрут (который я тестировал, и он хорошо работает). Вы можете изменить «20» в цикле 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;
}
}
Далее следует значительно лучшая реализация tracert на C#, чем существовала в других ответах до сих пор.
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;
}
}
}
Исправленные здесь подводные камни, которые присутствуют в других ответах, включают:
maxTTL реализован, поэтому функция не работает вечно.bufferSize, совместимый с другими реализациями tracert.Как насчет утилизации объекта pinger?
Вы можете показать нам реализацию этого кода? то есть: как это назвать.
@FlyingV: вы вызываете функцию, и маршруты возвращаются. var routes = GetTraceRoute("google.com");
пинг: мы можем использовать класс Ping, встроенный в .NET Framework.
Создайте экземпляр Ping и подпишитесь на событие PingCompleted:
Ping pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
Добавьте код для настройки и действия с пингом, например:
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:
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();
}
Это самый эффективный способ, который я мог придумать. Пожалуйста, проголосуйте, если вам это нравится, чтобы другие могли получить пользу.
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);
}
}
}
В следующем примере кода демонстрируется синхронное использование класса Ping. См. Класс Ping.