При использовании Windows API для написания функции пинга воспользуемся библиотекой ICMP (icmp.dll), которая предоставляет интерфейс для работы с одноименным протоколом. В этой библиотеке реализованы три функции, с которыми в дальнейшем мы будем работать. В интерпретации Delphi их объявления выглядят следующим образом:
function IcmpCreateFile:Thandle; StdCall;
function IcmpCloseHandle (H:Thandle):Bool; StdCall;
Первая из них (IcmpCreateFile) создает соединение, с которым мы собираемся работать. Вторая закрывает его, а третья посылает через установленное соединение соответствующие данные.
Остановимся подробнее на функции IcmpSendEcho. Принимаемые ею параметры "звучат" следующим образом:
IcmpHandle - идентификатор соединения, установленного при помощи IcmpCreateFile;
DestinationAddress - адрес пингуемого хоста;
RequestData - буфер с данными, которые посылаются при запросе;
RequestSize - размер буфера запроса;
RequestOptions - дополнительные свойства запроса;
ReplyBuffer - адрес буфера для приема результата;
ReplySize - размер буфера приема;
Timeout - время, в течение которого мы ожидаем ответа от хоста;
результат функции - количество записей типа ICMP_ECHO_REPLY, сохраненных в ReplyBuffer. Статус каждой записи хранится в соответствующем поле этой записи. При неудачном вызове функция возвращает значение NULL; дополнительная информация доступна при вызове GetLastError.
Структура ICMP_ECHO_REPLY имеет следующий вид:
Ticmp_echo_reply=record Address: TipAddr; // Ответивший адрес Status: integer; // Статус ответа RoundTripTime: integer; // Время прохождения пакета DataSize: word; // Размер данных ответа в байтах Reserved: word; // Зарезервировани Data: pointer; // Указатель на буфер с ответом Options: Toption_Information; // Опции ответа. End;
Помимо нее, мы можем использовать расширенный вариант структуры ICMP_ECHO_REPLY:
TsmICMP_Echo_Reply=record Address: TipAddr; // Ответивший адрес Status: integer; // Статус ответа RoundTripTime: integer; // Время прохождения пакета DataSize: word; // Размер данных ответа в байтах Reserved: word; // Зарезервировани Data: pointer; // Указатель на буфер с ответом Options: Toption_Information; // Опции ответа. Data: array [0..255] of Char; end;
Теперь для реализации пинга хоста мы:
создаем соединение;
вызываем ICMPSendEcho;
обрабатываем результат;
закрываем соединение.
Эти действия удобно оформить в виде процедуры:
procedure Ping (const Address, EchoString: PChar; var PingReply: TsmICMP_Echo_Reply; const PingTimeout: Integer = 500); var IPAddress: TipAddr; ICMPPort: THandle; begin // Конвертация IP в понятный для API формат IPAddress:= inet_addr (Address); // Проверка корректности конвертации if (IPAddress = INADDR_NONE) then begin raise Exception.Create ('Function call inet_addr failed. ' + 'The IP address is probably invalid.'); end; // Открытие соединения ICMPPort:= IcmpCreateFile (); // Проверка правильности открытия if (ICMPPort = INVALID_HANDLE_VALUE) then begin raise Exception.Create ('Function call IcmpCreateFile failed.'); end; // Отправка запроса "пинг" IcmpSendEcho (ICMPPort, IPAddress, EchoString, Length (EchoString), nil, @PingReply, SizeOf (PingReply), PingTimeout); // Закрытие соединения IcmpCloseHandle (ICMPPort); end;
Теперь при использовании в коде программы конструкции: