Wykorzystanie ICMP (IdIcmpClient) z pakietu Internet Direct (INDY)

rk7771

Artykuł pokazujący gotowe zastosowanie komponentu ICMP z pakietu Internet Direct (INDY)

***


Wykorzystanie komponentu ICMP z pakietu Internet Direct (INDY).

Poniżej przedstawię zastosowanie komponentu ICMP: IdIcmpClient z pakietu Internet Direct (INDY) w środowisku Delphi na przykładzie prostego programu Ping. Komponent IdIcmpClient dostępny jest w zakładce Indy Clients.

Zbudowanie okienkowego klienta pakietu ICMP (popularnego polecenia PING) w środowisku Delphi należy rozpocząć od umieszcenia na formie podstawowych komponentów jak na przykład:

  • pola Edit dla adresu IP lub nazwy FQDN,
  • przycisku Button do uruchomienia polecenia IdIcmpClient.Ping,
  • komponentu RichEdit lub Memo do zwrotnego pokaznia wyniku działania polecenia Ping,
  • komponentów SpinEdit w celu określenia ilości wykonań polecenia ICMP oraz ustalenia maksymalnego czasu odpowiedzi IdIcmpClient1.ReceiveTimeout.
Oczywiście wszystkie niezbędne informacje można wprowadzić bezpośrednio w kodzie źródłowym.

Ostatnim elementem jest dodanie komponentu IdIcmpClient z palety Indy Clients.

Po umieszczeniu wszystkich niezbędnych elementów można przejść do oprogramowania działania pakietu ICMP. Rozpoczynamy od wyczyszczenia pola Edit, komponentu RichEdit, ustawienia wartości komponentów SpinEdit.

Wstępną parametryzację realizujemy w procedurze FormCreate naszego programu:

procedure Tping_indy_form.FormCreate(Sender: TObject);
begin
  Edit_adres_ip.Clear;
  SpinEdit_ping_ilosc.Value := 10;
  SpinEdit_ping_czas_odpowiedzi.Value := 500;
  RichEdit_log.Clear;
  RichEdit_log.ScrollBars := ssVertical;
end;

Kolejne czynności jakie musimy wykonać:

  • uruchomić działanie pakietu ICMP po naciśnieciu przycisku Button,
  • oprogramować wlaściwości procedury OnReply komponentu IdIcmpClient1Reply wraz ze zwrotną informacją umieszczaną w komponencie RichEdit.

Przykładowy kod uruchomienia przycisku Button:

procedure Tping_indy_form.btn_uruchom_pingClick(Sender: TObject);
var
  i : integer;
begin
  if Length(Edit_adres_ip.Text)>0 then
  begin
    il_wyk := 0;
    RichEdit_log.Clear;
    IdIcmpClient1.Host := Edit_adres_ip.Text;
    IdIcmpClient1.PacketSize := 32;
    IdIcmpClient1.ReceiveTimeout := SpinEdit_ping_czas_odpowiedzi.Value;
    for I := 0 to SpinEdit_ping_ilosc.Value - 1 do
    begin
      try
        inc(il_wyk);
        IdIcmpClient1.Ping;
        SendMessage(RichEdit_log.Handle, WM_VSCROLL, SB_BOTTOM, 0);
      except
        on E: Exception do
        begin
          if CheckBox_pokaz_bledy_pakietu_icmp.Checked then
          begin
            RichEdit_log.Lines.Add('Błąd kontroli dla hosta: ' + IdIcmpClient1.Host);
            RichEdit_log.Lines.Add(E.Message);
          end;
        end;
      end;
    end;
  end;
end;

Kod: SendMessage(RichEdit_log.Handle, WM_VSCROLL, SB_BOTTOM, 0); spowoduje przewinięcie zawartości RichEdit na sam koniec co jest przydatne podczas obserwacji dużej ilości powtórzeń.

Przykładowy kod procedury OnReply komonentu IdIcmpClient1Reply:

procedure Tping_indy_form.IdIcmpClient1Reply(ASender: TComponent;
  const AReplyStatus: TReplyStatus);
var
  sTime : string;
begin

  With AReplyStatus Do
  begin
    if AReplyStatus.ReplyStatusType=rsEcho then
    begin
      if AReplyStatus.FromIpAddress <> '0.0.0.0' then
      begin
        if (AReplyStatus.MsRoundTripTime = 0) then
          sTime := '<='  //ustawienie wartości zmiennej dla wartości mniejszych niż 0
        else
          sTime := '=';  //ustawienie wartości zmiennej dla pozostałych wartości

        if AReplyStatus.MsRoundTripTime = 0 then
        begin
          //zamiana wartości MsRoundTripTime równej zero na wartość jeden
          RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + Format('%-1d bytes from %-16s Sequence ID=%-10d TTL=%-4d Time%s%d ms',
            [AReplyStatus.BytesReceived,
            AReplyStatus.FromIpAddress,
            AReplyStatus.SequenceId,
            AReplyStatus.TimeToLive,
            sTime,
            1]));
        end;
        if AReplyStatus.MsRoundTripTime > 0 then
        begin
          RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + Format('%-1d bytes from %-16s Sequence ID=%-10d TTL=%-4d Time%s%d ms',
            [AReplyStatus.BytesReceived,
            AReplyStatus.FromIpAddress,
            AReplyStatus.SequenceId,
            AReplyStatus.TimeToLive,
            sTime,
            AReplyStatus.MsRoundTripTime]));
        end;
      end;
    end;

    if (AReplyStatus.ReplyStatusType=rsTimeOut) or (AReplyStatus.FromIpAddress = '0.0.0.0') then
    begin
      RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. Host ' + IdIcmpClient1.Host + ' niedostępy');
    end;

    if AReplyStatus.ReplyStatusType=rsError then
    begin
      RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + IdIcmpClient1.Host + ' - nieznany błąd');
    end;

    if AReplyStatus.ReplyStatusType=rsErrorUnreachable then
    begin
      RichEdit_Log.Lines.Add(Format(inttostr(il_wyk) + '. Host: %d - adres sieciowy nie osiągalny [destination network unreachable]',
        [AReplyStatus.FromIpAddress]));
    end;

    if AReplyStatus.ReplyStatusType=rsErrorTTLExceeded then
    begin
      RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + Format('Połączenie %d %s: TTL wygasło.',
        [AReplyStatus.TimeToLive,AReplyStatus.FromIpAddress]));
    end;
  end;
  Application.ProcessMessages;
end;

Wprowadzenie w polu edycyjnym "adres IP" słownej pełnej wartości FQDN (fully qualified domain name) jak na przykład 360dni.pl również poprawnie wykona polecenie ICMP pakietu INDY.

Poniżej cała zawartość kodu źródłowego, kod napisany został w środowisku Delphi 10.1 Berlin:

unit ping_indy_unit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls,
  Vcl.Samples.Spin, IdBaseComponent, IdComponent, IdRawBase, IdRawClient,
  IdIcmpClient;

type
  Tping_indy_form = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    RichEdit_log: TRichEdit;
    Label1: TLabel;
    Label2: TLabel;
    Edit_adres_ip: TEdit;
    Label3: TLabel;
    SpinEdit_ping_ilosc: TSpinEdit;
    btn_uruchom_ping: TButton;
    btn_koniec: TButton;
    IdIcmpClient1: TIdIcmpClient;
    CheckBox_pokaz_bledy_pakietu_icmp: TCheckBox;
    Label4: TLabel;
    SpinEdit_ping_czas_odpowiedzi: TSpinEdit;
    procedure FormCreate(Sender: TObject);
    procedure btn_uruchom_pingClick(Sender: TObject);
    procedure IdIcmpClient1Reply(ASender: TComponent;
      const AReplyStatus: TReplyStatus);
    procedure btn_koniecClick(Sender: TObject);
  private
    { Private declarations }
    il_wyk : integer;  //ilość wykonań pakietu ICMP
  public
    { Public declarations }
  end;

var
  ping_indy_form: Tping_indy_form;

implementation

{$R *.dfm}

procedure Tping_indy_form.btn_koniecClick(Sender: TObject);
begin
  close;
end;

procedure Tping_indy_form.btn_uruchom_pingClick(Sender: TObject);
var
  i : integer;
begin
  if Length(Edit_adres_ip.Text)>0 then
  begin
    il_wyk := 0;
    RichEdit_log.Clear;
    IdIcmpClient1.Host := Edit_adres_ip.Text;
    IdIcmpClient1.PacketSize := 32;
    IdIcmpClient1.ReceiveTimeout := SpinEdit_ping_czas_odpowiedzi.Value;
    for I := 0 to SpinEdit_ping_ilosc.Value - 1 do
    begin
      try
        inc(il_wyk);
        IdIcmpClient1.Ping;
        SendMessage(RichEdit_log.Handle, WM_VSCROLL, SB_BOTTOM, 0);
      except
        on E: Exception do
        begin
          if CheckBox_pokaz_bledy_pakietu_icmp.Checked then
          begin
            RichEdit_log.Lines.Add('Błąd kontroli dla hosta: ' + IdIcmpClient1.Host);
            RichEdit_log.Lines.Add(E.Message);
          end;
        end;
      end;
    end;
  end;
end;

procedure Tping_indy_form.FormCreate(Sender: TObject);
begin
  Edit_adres_ip.Clear;
  SpinEdit_ping_ilosc.Value := 10;
  SpinEdit_ping_czas_odpowiedzi.Value := 500;
  RichEdit_log.Clear;
  RichEdit_log.ScrollBars := ssVertical;
end;

procedure Tping_indy_form.IdIcmpClient1Reply(ASender: TComponent;
  const AReplyStatus: TReplyStatus);
var
  sTime : string;
begin

  With AReplyStatus Do
  begin
    if AReplyStatus.ReplyStatusType=rsEcho then
    begin
      if AReplyStatus.FromIpAddress <> '0.0.0.0' then
      begin
        if (AReplyStatus.MsRoundTripTime = 0) then
          sTime := '<='  //ustawienie wartości zmiennej dla wartości mniejszych niż 0
        else
          sTime := '=';  //ustawienie wartości zmiennej dla pozostałych wartości

        if AReplyStatus.MsRoundTripTime = 0 then
        begin
          //zamiana wartości MsRoundTripTime równej zero na wartość jeden
          RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + Format('%-1d bytes from %-16s Sequence ID=%-10d TTL=%-4d Time%s%d ms',
            [AReplyStatus.BytesReceived,
            AReplyStatus.FromIpAddress,
            AReplyStatus.SequenceId,
            AReplyStatus.TimeToLive,
            sTime,
            1]));
        end;
        if AReplyStatus.MsRoundTripTime > 0 then
        begin
          RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + Format('%-1d bytes from %-16s Sequence ID=%-10d TTL=%-4d Time%s%d ms',
            [AReplyStatus.BytesReceived,
            AReplyStatus.FromIpAddress,
            AReplyStatus.SequenceId,
            AReplyStatus.TimeToLive,
            sTime,
            AReplyStatus.MsRoundTripTime]));
        end;
      end;
    end;

    if (AReplyStatus.ReplyStatusType=rsTimeOut) or (AReplyStatus.FromIpAddress = '0.0.0.0') then
    begin
      RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. Host ' + IdIcmpClient1.Host + ' niedostępy');
    end;

    if AReplyStatus.ReplyStatusType=rsError then
    begin
      RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + IdIcmpClient1.Host + ' - nieznany błąd');
    end;

    if AReplyStatus.ReplyStatusType=rsErrorUnreachable then
    begin
      RichEdit_Log.Lines.Add(Format(inttostr(il_wyk) + '. Host: %d - adres sieciowy nie osiągalny [destination network unreachable]',
        [AReplyStatus.FromIpAddress]));
    end;

    if AReplyStatus.ReplyStatusType=rsErrorTTLExceeded then
    begin
      RichEdit_Log.Lines.Add(inttostr(il_wyk) + '. ' + Format('Połączenie %d %s: TTL wygasło.',
        [AReplyStatus.TimeToLive,AReplyStatus.FromIpAddress]));
    end;
  end;
  Application.ProcessMessages;
end;

end.

Przykład wielowątkowego klienta pakietu ICMP w oparciu o komponenty INDY dostępny jest na stronie .

1 komentarz