AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi TIdIcmpClient im Thread
Thema durchsuchen
Ansicht
Themen-Optionen

TIdIcmpClient im Thread

Ein Thema von Jackie1983 · begonnen am 10. Mär 2010 · letzter Beitrag vom 21. Jun 2010
 
Astat

Registriert seit: 2. Dez 2009
Ort: München
320 Beiträge
 
Lazarus
 
#2

Re: TIdIcmpClient im Thread

  Alt 10. Mär 2010, 20:35
Hallo ackie1983, ICMP requests sind normalerweise verbindungsorientiert = Blockierend.
Wie dies bei den Indys implementiert ist, kann ich nicht sagen, kenn ich nicht.
Allerdings hab ich da noch im Hinterkopf, dass es da auch einen Port, normalerwiese 7 = Pingport
bei der Komponente einzutragen ist. Dies deutet auf eien AF_INET socket hin. Bei dem muss der
Port 7 dann offen sein, ist aber seit XP mit FW nicht mehr der Fall. Hier helfen nur ICMP Packete
auf RAW Socket Basis.

Anbei modifiziertes Sample von Narses.

Delphi-Quellcode:

unit uPingThread;

interface

uses
  windows,
  winsock,
  Sysutils,
  Classes;

const
  PACKET_SIZE = 32;
  ICMP_ECHO_REQUEST = 8;

type
  PICMP = ^TICMP;
  TICMP = packed record
    Typ : Byte;
    Code : Byte;
    CheckSum : Word;
    ID : Word;
    Seq_Num : Word;
    Data : array[1..PACKET_SIZE] of Byte;
  end;

  TPingCallBack = function(ErrorCode: integer; nMsec: integer;
    const AMsg: string; AICMP: TICMP): Boolean of object;

  TPingThread = class(TThread)
  private
    FPingCallBack: TPingCallBack;
    FIPAddr: string;
    FICMP: TICMP;
    procedure Ping;
  public
    procedure Execute; override;
    constructor Create(const AIPAddr: string; APingCallBack: TPingCallBack);
    destructor Destroy; override;
  end;

implementation

var
  _WsadData : TWsaData;
  _SeqNum : Word = 0;
  _SeqID : Word = Word(-1);
  _SocketLock : TRTLCriticalSection;

procedure TPingThread.Ping;
var
  Addr: TSockAddr;
  Sock: TSocket;
  ICMP: TICMP;
  ICMPret: PICMP;
  i: Integer;
  Start, Ende: Integer;
  Read: TFDSet;
  TimeOut: TTimeVal;
  buf: array [0..1023] of Byte;
  IPHeaderLen, IPLen: Integer;
  Checksum: Word;
  CheckSumTemp: Integer;
  pw: PWord;
  nMsec: integer;
begin
  nMsec := Integer(-1);
  try
    nMsec := Integer(-1);
    ZeroMemory(@FICMP, SizeOf(TICMP));

    EnterCriticalSection(_SocketLock);
    try
      if _SeqNum = word(-1) then _SeqNum := 0;
      Inc(_SeqNum);

      if _SeqID = 0 then _SeqNum := word(-1);
      Dec(_SeqID);
    finally
      LeaveCriticalSection(_SocketLock);
    end;

    Sock := Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if Sock = invalid_Socket then begin
      FPingCallBack(WSAGetLastError, -1, SysErrorMessage(WSAGetLastError),
        FICMP);
      Exit;
    end;
    try
      EnterCriticalSection(_SocketLock);
      try
        ICMP.Typ := ICMP_ECHO_REQUEST;
        ICMP.Code := 0;
        ICMP.CheckSum := 0;
        ICMP.ID := _SeqID;
        ICMP.Seq_Num := swap(_SeqNum);

        FillChar(ICMP.Data, Length(ICMP.Data), 9);

        pw := @ICMP;
        CheckSum := 0;
        for i := 1 to sizeof(ICMP) div 2 do begin
          CheckSumTemp := CheckSum + not(swap(pw^));
          CheckSum := CheckSumtemp and $FFFF;
          inc(CheckSum,(CheckSumTemp and $10000) shr 16);
          inc(pw);
        end;
        if sizeof(ICMP) mod 2 = 1 then begin
          CheckSumTemp := CheckSum + not(swap(word(ICMP.data[high(ICMP.data)])));
          CheckSum := CheckSumtemp and $FFFF;
          inc(CheckSum, (CheckSumTemp and $10000) shr 16);
        end;
        ICMP.CheckSum:=swap(CheckSum);

        addr.sin_family := AF_INET;
        addr.sin_port := 0;
        addr.sin_addr.S_addr := Inet_Addr(PAnsiChar(FIPAddr));
      finally
        LeaveCriticalSection(_SocketLock);
      end;

      if sendto(sock, ICMP, sizeof(ICMP), 0, addr, sizeof(Addr)) =
        Socket_Error then
      begin
        FPingCallBack(WSAGetLastError, -1, SysErrorMessage(WSAGetLastError),
          FICMP);
        Exit;
      end;
      start := gettickcount;
      FD_ZERO(Read);
      FD_Set(sock,Read);
      TimeOut.tv_sec := 2;
      TimeOut.tv_usec := 0;
      if Select(0, @Read, nil, nil, @TimeOut) > 0 then begin
        IPLen := recv(sock, buf, length(buf), 0);
        Ende := gettickcount;

        if IPLen = Socket_Error then
          raise Exception.Create(
            'Fehler bei recv' + #13#10 +
              SysErrorMessage(WSAGetLastError));

        if ((buf[0] and $F0) shr 4 = 4) then begin
          IPHeaderlen := (buf[0] and $0F) * 4;

          if IPHEaderlen + sizeof(ICMP) < IPLen then
            raise Exception.Create('Antwortpaket zu kurz');

          ICMPret := @buf[IPHeaderlen];

          move(ICMPret^, FICMP, SizeOf(TICMP));
          case ICMPret^.Typ of
            0 : begin
                  nMsec := Ende - Start;
                  FPingCallBack(WSAGetLastError, nMsec,
                    format(FIPAddr + ' Antwort in %d ms erhalten', [nMsec]),
                      FICMP);
            end;
            3 : FPingCallBack(WSAGetLastError, nMsec,
                  FIPAddr + ' Ziel nicht erreichbar Error ' +
                    IntToStr(ICMPret^.Code), FICMP);

            11: FPingCallBack(WSAGetLastError, nMsec,
                  FIPAddr + ' Zeitlimit (TTL) überschritten' +
                    IntToStr(ICMPret^.Code), FICMP);

            else
              FPingCallBack(WSAGetLastError, nMsec,
                  format(FIPAddr + ' Unbekannte Antwort: Typ %d',
                    [ICMPret^.Code]), FICMP);
          end;
        end else
          FPingCallBack(WSAGetLastError, nMsec,FIPAddr +
            ' Kann IPv6 nicht lesen.', FICMP);
      end else
        FPingCallBack(WSAGetLastError, nMsec, FIPAddr + ' TimeOut',FICMP);
    finally
      closesocket(sock);
    end;
  except
    on e: exception do begin
      FPingCallBack(WSAGetLastError, nMsec, e.Message, FICMP);
    end;
  end;
end;

{ TPingThread }

constructor TPingThread.Create(const AIPAddr: string;
  APingCallBack: TPingCallBack);
begin
  inherited create(true);
  FreeOnTerminate := true;
  FPingCallBack := APingCallBack;
  if @FPingCallBack = nil then
    Raise Exception.Create('TPingCallBack not assigned!');
  FIPAddr := AIPAddr;
  ZeroMemory(@FICMP, SizeOf(TICMP));
  Resume;
end;

destructor TPingThread.Destroy;
begin
  inherited;
end;

procedure TPingThread.Execute;
begin
  Ping;
  Sleep(30);
  Ping;
  Sleep(30);
  Ping;
  Sleep(30);
end;

initialization
  if (WSAStartup($0020, _WsadData) <> S_OK) then
    raise Exception.Create('WSAStartup: ' + IntToStr(WSAGetLastError));
  InitializeCriticalSection(_SocketLock);
finalization
  DeleteCriticalSection(_SocketLock);
  if (WSACleanup <> S_OK) then
    raise Exception.Create('WSACleanup: ' + IntToStr(WSAGetLastError));
end.
Verwendung:

Delphi-Quellcode:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, uPingThread, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;


type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    function PingCallBack(ErrorCode: integer; nMsec: integer;
      const AMsg: string; AICMP: TICMP): boolean;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


function TForm1.PingCallBack(ErrorCode: integer; nMsec: integer;
    const AMsg: string; AICMP: TICMP): boolean;
begin
  memo1.Lines.Add(AMsg);
  result := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TPingThread.Create('10.1.10.8', PingCallBack);
  TPingThread.Create('10.7.1.11', PingCallBack);
  TPingThread.Create('10.3.1.9', PingCallBack);
  TPingThread.Create('10.5.10.91', PingCallBack);
end;

end.

lg. Astat
Lanthan Astat
06810110811210410503210511511603209711003210010110 9032084097103
03211611111604403209711003210010110903210010510103 2108101116122
11610103209010110510810103206711110010103210511003 2068101108112
10410503210310111509910411410510109810111003211910 5114100046
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:02 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz