Сетевое железо - статьи

       

Windows API


При использовании Windows API для написания функции пинга воспользуемся библиотекой ICMP (icmp.dll), которая предоставляет интерфейс для работы с одноименным протоколом. В этой библиотеке реализованы три функции, с которыми в дальнейшем мы будем работать. В интерпретации Delphi их объявления выглядят следующим образом:

function IcmpCreateFile:Thandle; StdCall;

function IcmpCloseHandle (H:Thandle):Bool; StdCall;

function IcmpSendEcho (IcmpHandle:Thandle;
DestinationAddress:TipAddr;
RequestData:pointer;
RequestSize:word;
RequestOptions:POption_Information;
ReplyBuffer:pointer;
ReplySize:integer;
Timeout:integer):Integer; 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;


Теперь при использовании в коде программы конструкции:

Ping ('127.0.0.1',nil,Reply,5000);

в переменной Reply мы получим результат пинга.


Содержание раздела