Polecenia ping nie trzeba nikomu chyba przedstawiać. Służy ono do diagnozowania połączeń sieciowych. Dzięki niemu można sprawdzić, czy istnieje połączenia między dwoma hostami, jaka jest jakość tego połączenia oraz jakie występują opóźnienia. Dodatkowo jeśli podajemy adres hosta nie w postaci adresu IP to możemy zdiagnozować, czy poprawnie rozwiązywane są nazwy przez serwer DNS. Wspomniane powyżej możliwości czasami potrzebne są w trakcie programowania systemów informatycznych działających w sieci. Czasami chcemy sprawdzić, czy dany host odpowiada, jaka jest jakość połączenia z hostem, czy udaje nam się poprawnie rozwiązać nazwę domenową na adres IP. W tym celu w .net zaimplementowano polecenie PING. Stworzono klasę o takiej samej nazwie.

Obiekty tej klasy używa się równie łatwo jak wbudowane systemowe polecenie PING. Podstawowy scenariusz użycia można zapisać w postaci następującego kodu:

Ping ping = new Ping();
PingReply reply = ping.Send("www.jankowskimichal.pl");
if (reply.Status == IPStatus.Success)
  {
     Console.WriteLine("Address: {0}", reply.Address.ToString());
     Console.WriteLine("RoundTrip time: {0}", reply.RoundtripTime);
     Console.WriteLine("Time to live: {0}", reply.Options.Ttl);
     Console.WriteLine("Don't fragment: {0}", reply.Options.DontFragment);
     Console.WriteLine("Buffer size: {0}", reply.Buffer.Length);
  }
else
  {
     Console.WriteLine(reply.Status);
  }

Analizując kod widzimy, że w pierwszej kolejności wysyłamy pakiet testujący na podany adres. W naszym przypadku jest to adres bloga. W odpowiedzi dostajemy obiekt PingReply, który przechowuje w sobie wszystkie potrzebne informacje, które następnie są wyświetlanie na konsoli.

Doświadczony programista od razu powinien zauważyć pewien błąd. Choć może nie powinno być to nazywane błędem, a jedynie nie wydajnie napisanym kodem. Otóż od momentu wysłanie zapytania do uzyskania odpowiedzi może upłynąć sporo czasu. W tym rozwiązaniu program czeka na tą odpowiedź, choć mógłby wykorzystać ten czas na robienie innych pożytecznych rzeczy.

W celu poprawienie wydajności tego rozwiązania należy wywołać polecenie PING w sposób asynchroniczny. Powinniśmy wysłać polecenie PING. Następnie zająć się innymi rzeczami, a w sytuacji nadejścia odpowiedzi powrócić do polecenia PING i obsłużyć go tak jak chcieliśmy oraz wysłać informację że zakończyliśmy przetwarzanie polecenia PING i możemy przejść do dalszego wykonywanie programu. W tym celu należy zdefiniować metodę, która wykona się po przyjściu odpowiedzi na komendę PING. W niej to powinniśmy zawrzeć kod, który ma przetworzyć otrzymaną odpowiedź. W przykładzie kod ten będzie tylko wypisywał podstawowe informacje:

private void ping_PingCompleted(object sender, PingCompletedEventArgs e)
    {
      //Sprawdzamy, czy operacja nie została przerwana
      if (e.Cancelled)
      {
        System.Console.WriteLine("Ping was cancelled...");
      }
      else
      {
        //Sprawdzamy, czy nie wystąpił błąd
        if (e.Error != null)
        {
          System.Console.WriteLine("An error occurred: " + e.Error);
        }
        else
        {
          //Wyświetlamy odpowiedź
          if (e.Reply != null)
          {
            if (e.Reply.Status == IPStatus.Success)
            {
              System.Console.WriteLine("Reply from " + e.Reply.Address.ToString()
                + ": bytes=" + e.Reply.Buffer.Length
                + " time=" + e.Reply.RoundtripTime
                + " TTL=" + e.Reply.Options.Ttl);
            }
            else
            {
              System.Console.WriteLine("Ping was unsuccessful: " + e.Reply.Status);
            }
          }
          else
          {
            System.Console.WriteLine("There was no response.");
          }
        }
      }
      //Przywrócenie wykonywania wątku głównego
      ((AutoResetEvent)e.UserState).Set();
    }

Mając zdefiniowaną metodę obsługujące odpowiedź otrzymaną na polecenie PING możemy przejść sposobu wysłania polecenia PING. Podobnie jak poprzednio należy zacząć od zdefiniowania polecenia PING. W tym przykładzie można zobaczyć w jaki sposób konfigurowane są różne opcje tego polecenia:

  • timeout polecenia,
  • dane do wysłania z poleceniem PING,
  • TTL polecenia,
  • możliwość fragmentacji pakietu.

Jedyną różnicą w stosunku do poprzedniej wersji jest sposób wysłania pakietu. W poprzednim przypadku została użyta metoda Send(…). Natomiast w tym używana jest metoda SendAsync(…). Należy tylko pamiętać, że przed wysłaniem pakietu powinno się zdefiniować metodę, która zostanie wykonana w momencie zakończenia polecenia PING. Oraz dodatkowo zatrzymać wykonywanie tego wątku do momentu obsłużenia polecenia PING.

  AutoResetEvent autoResetEvent = new AutoResetEvent(false);

  //Tworzymy obiekt ping
  Ping ping = new Ping();

  //Podpinamy metodę, która ma się wykonać po zakończeniu polecenia ping
  ping.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);

  //Tworzymy 32 bajty do wysłania
  string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
  byte[] buffer = Encoding.ASCII.GetBytes(data);

  //Ustawiamy timeout na 10 sekund
  int timeout = 10000;

  //Ustawiamy inne opcje:
  //- TTL na 32
  //- brak możliwości fragmentacji pakietu
  PingOptions options = new PingOptions(32, true);

  //Wysyłamy ping
  ping.SendAsync("www.jankowskimichal.pl", timeout, buffer, options, autoResetEvent);

  //Wstrzymujemy główny wątek do momentu otrzymania odpowiedzi
  autoResetEvent.WaitOne();