Delphi: Ping

Продолжаю собирать свои исходники с недр винчестеров. У нас есть система мониторинга zabbix. С некоторых серверов с помощью zabbix проверяется доступность тех или иных сетей. Для этого естественно нужно что-то пинговать. Вся беда в том, что zabbix при опросе того или иного тригера ожидает в течении 5-ти секунд какого-либо цифрового значения.  И тут стандартный вывод команды ping не подходит, так как он кроме самого времени ответа выдает кучу лишних букв и символов, не говоря уже о том, что о таймауте утилита ping сообщает не цифровым значением, а текстом "Превышен интервал ожидания для запроса.".

Потому когда-то давно для этих целей я решил написать свою утилиту ping. Сейчас я конечно все бы сделал с помощью скрипта: вырезал бы из вывода стандартной команды ping нужные символы, а текст "Превышен интервал ожидания для запроса" заменил бы на значение 4999, но тогда я почему-то решил написать необходимую утилиту в delphi.

Ниже сохраню себе  исходный код, вдруг пригодиться.

program Project1;

{$APPTYPE CONSOLE}

uses
   SysUtils,
   WinSock,
   Windows; 

type
   ip_option_information = packed record 
      // Информация заголовка IP (Наполнение
      // этой структуры и формат полей описан в RFC791.
      Ttl : byte; // Время жизни (используется traceroute-ом)
      Tos : byte; // Тип обслуживания, обычно 0
      Flags : byte; // Флаги заголовка IP, обычно 0
      OptionsSize : byte; // Размер данных в заголовке, обычно 0, максимум 40
      OptionsData : Pointer; // Указатель на данные
   end;

   icmp_echo_reply = packed record
      Address : u_long; // Адрес отвечающего
      Status : u_long; // IP_STATUS (см. ниже)
      RTTime : u_long; // Время между эхо-запросом и эхо-ответом
      // в миллисекундах
      DataSize : u_short; // Размер возвращенных данных
      Reserved : u_short; // Зарезервировано
      Data : Pointer; // Указатель на возвращенные данные
      Options : ip_option_information; // Информация из заголовка IP
   end;

   PIPINFO = ^ip_option_information;
   PVOID = Pointer;

var
   hIP : THandle;
   pingBuffer : array [0..31] of Char;
   pIpe : ^icmp_echo_reply;
   pHostEn : PHostEnt;
   wVersionRequested : WORD;
   lwsaData : WSAData;
   error : DWORD;
   destAddress : In_Addr;
   reply_time,reply_time1,reply_time2:integer;
   f,l:TextFile;

function IcmpCreateFile() : THandle; stdcall; external 'ICMP.DLL' name 'IcmpCreateFile';
function IcmpCloseHandle(IcmpHandle : THandle) : BOOLean; stdcall; external 'ICMP.DLL' name 'IcmpCloseHandle';
function IcmpSendEcho(
      IcmpHandle : THandle; // handle, возвращенный IcmpCreateFile()
      DestAddress : u_long; // Адрес получателя (в сетевом порядке)
      RequestData : PVOID; // Указатель на посылаемые данные
      RequestSize : Word; // Размер посылаемых данных
      RequestOptns : PIPINFO; // Указатель на посылаемую структуру
      // ip_option_information (может быть nil)
      ReplyBuffer : PVOID; // Указатель на буфер, содержащий ответы.
      ReplySize : DWORD; // Размер буфера ответов
      Timeout : DWORD // Время ожидания ответа в миллисекундах
   ) : DWORD; stdcall; external 'ICMP.DLL' name 'IcmpSendEcho';
procedure R;
   var t: string;
   begin
      AssignFile(f,paramstr(2));
      Reset(f);
      Readln(f,t);
      Writeln(t);
   end;

procedure I;
   begin
      // Создаем handle
      hIP := IcmpCreateFile();
      GetMem( pIpe,
         sizeof(icmp_echo_reply) + sizeof(pingBuffer));
      pIpe.Data := @pingBuffer;
      pIpe.DataSize := sizeof(pingBuffer);
      wVersionRequested := MakeWord(1,1);
      error := WSAStartup(wVersionRequested,lwsaData);
      if (error <> 0) then
      begin
         writeln('Error in call to '+'WSAStartup().');
         writeln('Error code: '+IntToStr(error));
         Exit;
      end;
      pHostEn := gethostbyname(PChar(paramstr(2)));
      error := GetLastError();
      if (error <> 0) then
      begin
         writeln('Error in call to'+'gethostbyname().');
         writeln('Error code: '+IntToStr(error));
         Exit;
      end;
      destAddress := PInAddr(pHostEn^.h_addr_list^)^;

      // Посылаем ping-пакет
      IcmpSendEcho(hIP,destAddress.S_addr,@pingBuffer,sizeof(pingBuffer),Nil,pIpe,sizeof(icmp_echo_reply) + sizeof(pingBuffer),5000);
      error := GetLastError();
      if (error <> 0) then reply_time := 9999
      else reply_time := pIpe.RTTime;

      // Смотрим некоторые из вернувшихся данных
      if reply_time=0 then reply_time:=1;
      if (paramstr(3) = '-f')and(not(paramstr(5) = '-u')) then begin
         AssignFile(f,paramstr(4));
         Rewrite(f);
         Writeln(f,IntToStr(reply_time));
         Flush(f);
         CloseFile(f);
      end;
      if (paramstr(3) = '-f')and(paramstr(5) = '-u') then begin
         AssignFile(f,paramstr(4));
         if FileExists(paramstr(4)) then Append(f) else Rewrite(f);
         Writeln(f,IntToStr(reply_time));
         Flush(f);
         CloseFile(f);
      end;
      if (paramstr(3) = '-l') then begin
         AssignFile(l,paramstr(4));
         if FileExists(paramstr(4)) then Append(l) else Rewrite(l);
         Writeln(l,DateToStr(now)+' '+TimeToStr(now)+' ping1:'+IntToStr(reply_time1)+' ping2:'+IntToStr(reply_time2)+' ping_result:'+IntToStr(reply_time));
         Flush(l);
         CloseFile(l);
      end;
      writeln(IntToStr(reply_time));
      IcmpCloseHandle(hIP);
      WSACleanup();
      FreeMem(pIpe);
   end;
begin
   if (paramstr(1) = '/?') or (paramstr(1) = '-h') then begin
      writeln('-I IP_Address - Ping IP Address');
      writeln('-f File Address - Output File Address (Rewrite File), use this parametr only with -I');
      writeln('-u Update File, use this parametr only with -f');
      writeln('-r File Address - Read Information From File');
      writeln('-l File Address - Log File');
      writeln('-h - Help');
      writeln('/? - Help');
   end;
   if paramstr(1) = '-I' then I;
   if paramstr(1) = '-r' then R;
end.
Понравилось? =) Поделись с друзьями:

Обсудить