Продолжаю собирать свои исходники с недр винчестеров. У нас есть система мониторинга 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.