문제

대상 컴퓨터에 핑과 트레이서 로테를 수행하기 위해 C# 코드가 편리한 사람이 있습니까? Ping.exe 및 Tracert.exe 프로그램을 호출하고 출력을 구문 분석하는 순수한 코드 솔루션을 찾고 있습니다. 더 강력한 것을 원합니다.

도움이 되었습니까?

해결책

기본 클래스 라이브러리에는 포함되지만 , 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

다음은 C# 구현이 훨씬 더 나은 것입니다. tracert 지금까지 다른 답변에 존재합니다.

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 구현과 일치하는 옵션.
  • 매우 간결하고 깨끗합니다. 단일 방법으로 포함되어 있으며 여기서 다른 옵션보다 상당히 짧습니다.

핑 부품의 경우 핑 클래스 MSDN에서.

위의 Scotts 코드 답변에 대한 AM 개선으로 인해 목적지에 도달하기 전에 경로가 아무것도 끝나지 않으면 그의 솔루션이 작동하지 않는다는 것을 알았습니다. 절대 돌아 오지 않습니다. 적어도 부분 경로가있는 더 나은 솔루션은 이것 일 수 있습니다 (테스트하고 잘 작동합니다). For 루프의 '20'을 더 큰 또는 작은 것으로 변경하거나 다른 방식으로 반복 횟수를 제어하려면 너무 오래 걸리는 경우 감지하려고 시도 할 수 있습니다. 원래 코드에 대한 Scott에게 전체 크레딧 - 감사합니다.

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

: 우리는 사용할 수 있습니다 Ping .NET 프레임 워크에 내장 된 클래스.

인스턴스화 a 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();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top