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.
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 .
Super