Пингуем (ping) под delphi


Содержание

Маааленькое PING-приложеньице

Два интеpнетчика:
— Попингуй!
— От попингуя слышу.

Протокол Ping предназначен для тестирования компьютерных соединений в Интернете путём посылки через протокол Internet Protocol (IP) по обределённому адресу сообщения и ожидания от него ответа.

ICMP — Internet Control Message Protocol. ICMP служит для передачи сообщений об ошибках а так же управляющих сообщений . ICMP-тест может показать насколько быстро проходит информация между двумя узлами в Интернете.

  1. Запускаем Delphi;
  2. В Новом проекте добавляем в форму Tbutton, Tedit и Tmemo;
  3. Вставляем “winsock”;
  4. объявляем структурку для IP-заголовка:

  1. объявляем структурку для хранения ICMP пакета:

  1. Объявляем функции и процедуры, которые мы будем вызывать из ICMP.DLL

  1. В TButton в событие Onclick вставляем следующий код:

У данного примера есть один недостаток — программа не воспримет доменное имя, только IP-адресс. Для пользователей NT не используйте функцию IcmpCloseHandle.

Ну и в конце полный исходный код примера можно взять здесь.

Copyright © 2004-2020 «Delphi Sources». Delphi World FAQ

Определении пинга (ping) в Delphi.

Опубиковано: 24.03.2013 г., автор: , просмотров: 9591

Определение пинга с помощью Delphi

В этой статье я расскажу об определении пинга (ping) в Delphi. Думаю, вы все знакомы со стандартоной командой windows. Если нет, то нажимаем горячую клавишу Win+R и в появившем окне вводем cmd

Откроется командная строка, и в ней набираем ping + адрес сервера, к примеру адрес своего компьютера и нажимаем enter

Теперь тоже самое мы попробуем реализовать в Delphi. Создаем новый проект File->New->VCL Form Application и кидаем на форму следующие компоненты: TButton,TLabel, TEdit и TMemo. Для более красивого отображения, можно в настройках Memo изменить цвет шрифта (Font->Color).

Для проведения пинга воспользуемся следующей процедурой:

Пингование IP адреса

  • Группа: Пользователи
  • Сообщений: 179

Извеняюсь что в прошлый раз по глупому назвал тему. Наверное это от стресса.. :)

Дак воть вопрос.

Подсажите как в Дельфи пропинговать IP адрес удоленного компьютера (он же сервак).

Пытаюсь написать программку, которая будет записывать в отчёт время в которое была потеряна связь с серваком.

Может кто подскажет. чего-нибудь!

Сообщение отредактировал graleksey: 13.09.2007 — 10:38

Программа для работы с ping-сервисами. Продолжение.

Да, много времени прошло с того момента как я первый раз упомянул в блоге о программе “Пинговалка” написанной в Lazarus под Ubuntu. И теперь, спустя практически 10 месяцев с того момента, написана новая версия программы для работы с ping-сервисами. Правда, из-за неприятной неожиданности пришлось расстаться с идеей переноса всего проекта под Delphi. Но это не проблема, тем более, что последняя версия Lazarus стала вроде бы даже и по-шустрее.

Основным недостатком предыдущей версии было отсутствие многопоточности из-за чего проход по списку даже в 30 сервисов занимал достаточно продолжительное время. В новой версии этот недостаток ликвидирован. Но обо всем по порядку.

Во-первых, программа “полегчала” и весит теперь почти в три раза меньше. Изменился и её внешний вид. Вот, что было:

А вот, что стало:

Соответственно, добавились новые функции, а именно:

1. Теперь можно хранить список RSS-лент всех ваших блогов и не загружать их по отдельности при каждом запуске программы. Для сохранения ленты, достаточно записать ей URL в поле “Лента” и нажать [Enter] или кнопку “Обновить содержимое ленты” .

Если задан неправильный URL ленты, то Вы получите сообщение следующего содержания:

2. Ускорена загрузка содержимого ленты. Ускорение достигается не только тем, что Вы можете отрегулировать количество загружаемых элементов RSS-ленты, но и тем, что все данные принимаются в формате JSON, что значительно снижает “вес” принимаемых данных из Сети.

3. Добавлен фильтр выбора сервисов в списке. Теперь Вы можете выбирать из списка:

  • Все сервисы без исключения (было в предыдущей версии)
  • Только сервисы, которые один или более раз возвращали ошибку. Удобно использовать для ручного удаления нерабочих сервисов
  • Только сервисы, которые ни разу не возвращали ошибки.

4. Добавлены фильтры для авто-удаления нерабочих сервисов. Для удаления используются два фильтра:

  • по общему количеству ошибок. Если Вы установите его значение равным нулю, то сервис будет удален из списка при первой же ошибке.
  • по коду последней ошибки. При этом количество ошибок роли не играет – проверяется последняя.

Если включены оба фильтра, то сервис удаляется при срабатывании хотя бы одного из них.

5. Добавлена многопоточность. Можно сказать в связи с этой возможностью и затевалась вся “переделка” программы.

Теперь пинги могут отправляться в 1-15 потоках, что в значительной степени ускоряет работу программы. У меня пинг по 100 сервисам при количестве потоков — 10 проходит примерно за 8 секунд.

Ну и, конечно же, сохранились функции сохранения/загрузки списков сервисов из TXT/XML-файлов, а также авто-сохранение последнего рабочего списка.

Хорошее начало

Увлечённые тотальным проникновением информационных технологий в самые различные области человеческой деятельности, мы в последнее время совсем редко вспоминаем о собственно информатике — том базовом предмете, с которого и начиналось путешествие в увлекательный мир вычислительной техники для каждого, по крайней мере, из приобщившихся к ней в 80-ых и 90-ых годах. Но и для тех, кто только начинает постижение основ ИТ, на самом деле изменилось немногое: им точно так же приходится отыскивать кнопки на своих первых компьютерах и самостоятельно находить общий язык с электронным «разумом». Главное отличие между нами, начинавшими десять и более лет назад, и теми, кто начинает сегодня, скрывается в отсутствии простого и понятного языка программирования, который мог бы послужить этим универсальным средством общения. Такого, каким был когда-то BASIC.

Вспомните, BASIC был стандартом де-факто, подкупавшим своей предельной простотой и надёжностью. Программы на нём не требовали компиляции и в большинстве случаев запускались сразу, а ошибки, если и возникали, отлавливались в два счёта даже совершенным новичком. На очень многих бытовых платформах BASIC был основной рабочей средой, в которую пользователь попадал сразу же по включении компьютера: отечественные «Специалист» и РК-86, импортные «Спектрумы», «Энтерпрайзы», «Амиги», «Коммодоры» и многие, многие другие использовали BASIC, по сути, в качестве операционной системы, с помощью которой можно было управлять всеми небогатыми ресурсами тогдашних вычислительных машин. При том, что BASIC-диалектов существовало множество, совместимость между ними была достаточной для запуска без изменений значительной части программ. В результате всего этого для многих пользователей BASIC стал чуть ли не вторым родным языком, с помощью которого легко и быстро можно было формализировать любую задачу для дальнейшего её решения на компьютере. Признаться честно, я и по сей день, составляя какой-нибудь сложный алгоритм, использую в качестве промежуточного псевдоязыка BASIC-подобные конструкции и операторы.

«Опопсение» вычислительной техники, произошедшее за последние десять лет, обернулось популяризацией пользовательских интерфейсов и инструментов, позволяющих объяснить машине, чего человеку надо, приложив минимум усилий. Управление ресурсами машины теперь вообще не требует программирования: всё реализуется с помощью мыши и визуальных элементов, а под программированием молодое поколение понимает написание скриптов для Microsoft Word и составление табличек в Excel. Оно, может быть, и не так плохо. В конце концов, зачем среднему компьютерному пользователю быть программистом? Но отрицательные моменты тоже есть: во-первых, составление алгоритмов (читайте, умение отыскать самому и растолковать компьютеру наиболее эффективный способ решения задачи) для тех, кто сегодня заканчивает школу, задача неподъёмная (проверено лично мной на настоящих студентах), во-вторых, что показать начинающим, чтобы Windows не ассоциировалась у них с пупом Земли, а экселевская табличка не казалась вершиной программистского искусства?

BASIC, достать интерпретатор которого сегодня, конечно, можно, на роль универсальной рабочей среды уже не годится — про него мало кто знает. Python, на котором пишутся множество серьёзных программ, неплохой кандидат, но не идеальный — про него тоже слышали немногие. Идеалом мог бы стать инструмент, с которым сталкиваются каждый день большинство пользователей, и такой инструмент, по счастью, есть. Вы и сейчас работаете с ним. Это ваш веб-браузер и встроенный в него интерпретатор языка Javascript.

Идея выдвинуть Javascript на роль «Бейсика XXI века», изложена в книге Гарольда Дэвиса «Программирование в любом браузере». И согласитесь, идея подкупает. Вообще говоря, Javascript — сложный объектно-ориентированный язык, совместимость диалектов которого остаётся на некотором среднем уровне (стандарт существует, но разработчики большинства браузеров используют собственные имплементации). Но прелесть его в том, что, как и для BASIC, базовая функциональность Javascript может быть описана небольшим набором команд с простым и понятным синтаксисом, которые будут работать в любом браузере, под любой операционной системой. В то же время, тем, кто решит продолжить погружение, можно на примере Javascript объяснить и основы объектно-ориентированного подхода, показать как работают с современными форматами данных в Сети. Так что если у вас есть знакомый, который только начинает знакомство с программированием, покажите ему Javascript. В конце концов, когда-то кто-то точно так же рассказал вам о «Бейсике».

Счетчик посещений на Delphi

Счетчики предназначены для учета количества посетителей на Ваш сайт. Кроме этого на счетчик можно возложить операции ведения статистики, учет хостов откуда пришли посетители и т.д.

Данный пример демонстрирует работу простого текстового счетчика с ведением списка IP адресов посетителей.

Сначала пропишем обработчик WebActionItem

Осталось реализовать функцию SetCounter

И еще необходимо определить константы имен файлов const

Для работы этого скрипта необходимо создать два файла, для ведения счета и для списка IP. В файле счета необходимо установить начальное значение счетчика, сделать это можно в любом текстовом редакторе.

Пингуем (Ping) под Delphi

Протокол Ping предназначен для тестирования компьютерных соединений в Интернете путём посылки через протокол Internet Protocol (IP) по обределённому адресу сообщения и ожидания от него ответа.

ICMP — Internet Control Message Protocol. ICMP служит для передачи сообщений об ошибках а так же управляющих сообщений . ICMP -тест может показать насколько быстро проходит информация между двумя узлами в Интернете.

1. Запускаем Delphi;

2. В Новом проекте добавляем в форму Tbutton, Tedit и Tmemo;

3. Вставляем “winsock”;

4. объявляем структурку для IP-заголовка:

5. объявляем структурку для хранения ICMP пакета:

6. Объявляем функции и процедуры, которые мы будем вызывать из ICMP.DLL


7. В Tbutton в событие Onclick вставляем следующий код:

У данного примера есть один недостаток — программа не воспримет доменное имя, только IP-адресс. Для пользователей NT не используйте функцию IcmpCloseHandle. Это всё.

Ну, и в конце полный исходный код примера:

Получение списка DLL загруженных приложением

Иногда бывает полезно знать какими DLL-ками пользуется Ваше приложение. Давайте посмотрим как это можно сделать в Win NT/2000.

Для вызова приведённой функции надо сделать следующее:

  • Добавить listbox на форму (Listbox1)
  • Добавить кнопку на форму (Button1)
  • Обработчик события OnClick для кнопки будет выглядеть следующим образом

Файловые операции с использованием стандартного диалога с анимацией

В следующем примере используется функция SHFileOperation для копирования группы файлов и показа анимированного диалога. Вы можете использовать также следующие флаги для копирования, удаления, переноса и переименования файлов. TO_COPY, FO_DELETE, FO_MOVE, FO_RENAME

Примечание: буфер, содержащий имена файлов для копирования должен заканчиваться двумя нулевыми символами.

Delphi (XE2) Indy (10) Многопоточный пинг

У меня есть комната с 60 компьютерами/устройствами (40 компьютеров и 20 осциллографов Windows CE), и я хотел бы знать, кто и каждый жив, используя ping. Сначала я написал стандартный пинг (см. Здесь Delphi Indy Ping Error 10040), который теперь отлично работает, но требует времени, когда большинство компьютеров находятся в автономном режиме.

Итак, я пытаюсь написать MultiThread Ping, но я очень борюсь с ним. Я видел только очень мало примеров в Интернете, и никто не соответствовал моим потребностям, поэтому я сам пытаюсь написать его.

Я использую XE2 и Indy 10, и форма состоит только из памятки и кнопки.

Моя проблема в том, что она «кажется» работает, когда я раскомментирую «sleep (10)», и «кажется» не работает без него. Это, безусловно, означает, что я пропускаю точку в потоке, который я написал.

Иными словами. Когда Sleep (10) находится в коде. Каждый раз, когда я нажимал кнопку, чтобы проверить соединения, результат был правильным.

Без сна (10) он работает «больше всего» времени, но несколько раз результат неверен, давая мне эхо-пинг на автономных компьютерах и не пинговое эхо на онлайн-компьютере, равно как и ответ на пинг не был назначен к правильной нити.

Любые комментарии или помощь приветствуются.

—— РЕДАКТИРОВАТЬ/ВАЖНО ——

Как общее продолжение этого вопроса, @Darian Miller начал Проект Google Code здесь https://code.google.com/p/delphi-stackoverflow/, который является рабочей основой. Я отмечаю его ответ как «принятый ответ», но пользователи должны ссылаться на этот проект с открытым исходным кодом (весь кредит принадлежит ему), поскольку он, несомненно, будет расширен и обновлен в будущем.

Реми объяснил проблемы. Я хотел сделать это в Indy на некоторое время, поэтому я опубликовал возможное решение, которое я только что собрал в новый проект Google Code, вместо того, чтобы иметь длинный комментарий здесь. Это первая вещь, дайте мне знать, если у вас есть какие-то изменения для интеграции: https://code.google.com/p/delphi-vault/

Этот код имеет два способа для Ping. многопоточных клиентов, как в вашем примере, или с простой процедурой обратного вызова. Написано для Indy10 и более поздних версий Delphi.

В результате ваш код будет использовать потомки TThreadedPing, определяющие метод SynchronizedResponse:

И чтобы отключить некоторые потоки клиентов, код будет выглядеть примерно так:

Ответ на резьбу вызывается синхронным методом:

Корневая проблема заключается в том, что pings — это трафик без установления соединения. Если у вас есть несколько объектов TIdIcmpClient , которые пингоруют сеть в одно и то же время, один экземпляр TIdIcmpClient может получить ответ, который фактически принадлежит другому экземпляру TIdIcmpClient . Вы пытаетесь объяснить это в своем потоковом цикле, проверяя значения SequenceId , но вы не принимаете во внимание, что TIdIcmpClient уже выполняет ту же проверку внутри. Он считывает сетевые ответы в цикле, пока не получит ожидаемый ответ, или пока не произойдет ReceiveTimeout . Если он получает ответ, который он не ожидает, он просто отбрасывает ответ. Таким образом, если один экземпляр TIdIcmpClient отбрасывает ответ, ожидаемый другим экземпляром TIdIcmpClient , этот ответ не будет обрабатываться вашим кодом, а другой TIdIcmpClient скорее всего получит другой ответ TIdIcmpClient и т.д.). Добавляя Sleep() , вы уменьшаете (но не устраняете) вероятность того, что пинг будет перекрывать друг друга.

Для того, что вы пытаетесь сделать, вы не сможете использовать TIdIcmpClient as-is для одновременного запуска нескольких пингов, извините. Он просто не предназначен для этого. Невозможно отличить данные ответа так, как вам нужно. Вам придется сериализовать свои потоки, чтобы только один поток мог вызывать TIdIcmpClient.Ping() за раз.

Если сериализация pings не является для вас вариантом, вы можете попробовать скопировать части исходного кода TIdIcmpClient в свой собственный код. Есть 41 поток — 40 потоков устройств и 1 ответная нить. Создайте единый сокет, который разделяет все потоки. Подготовьте каждый поток устройств и отправьте его индивидуальный запрос ping в сеть с помощью этого сокета. Затем следует, чтобы поток ответов непрерывно читал ответы из того же самого сокета и перенаправлял их обратно к соответствующему потоку устройства для обработки. Это немного больше работы, но это даст вам многократный ping parallelism, который вы ищете.

Если вы не хотите идти на все эти проблемы, альтернатива заключается в том, чтобы просто использовать стороннее приложение, которое уже поддерживает одновременное пинирование нескольких машин, например FREEPing.

Пингуем (ping) под delphi

Команда ping служит для принудительного вызова ответа конкретной машины. Для этого используется дейтаграмма ECHO_REQUEST протокола ICMP. Это протокол низкого уровня, который не требует наличия серверных процессов на зондируемой машине; это хороший способ убедится в том, что питание машины включено и IP находится в поднятом состоянии. Успешный результат использования команды ping вовсе не обязательно означает, что выполняются какие-то сервисные программы высокого уровня.

Ping — хорошее средство проверки правильности конфигурации сети, поскольку в выполнении этой команды участвуют система маршрутизации, схемы разрешения адресов и сетевые шлюзы. Если данная команда не работает — можете быть совершенно уверены, что более сложные средства тем более не функционируют. Несмотря на свою простоту, ping — одна из главных рабочих лошадок, использующихся при отладке сетей.

Практика

Для практической реализации, как всегда, можно использовать несколько подходов. Первый из них — использование низкоуровневых функций API (к примеру, встроенных в библиотеку ICMP.DLL). Второй — использование высокоуровневых компонентов (к примеру, Indy >И у первого, и у второго способа есть свои позитивные и негативные моменты. Так, при использовании функций API откомпилированный код будет иметь гораздо меньшие размеры, нежели при использовании высокоуровневых компонентов,- да и производительность его будет выше (например, при одновременном пинге одной подсети с использованием потоков).

С другой стороны, компоненты можно использовать, имея только отдаленное представление о работе с протоколом ICMP, а также об использовании Windows API. Но, в то же время, компоненты порождают неоправданно большой исполняемый код, да и производительность в этом случае ниже. К счастью, сегодня разработчиками процессоров и памяти почти стерта грань между производительностью кода, написанного с использованием Windows API, и кода, написанного с использованием средств более высокого уровня абстракции (в нашем случае — компонентов Delphi).

На всякий случай приведем примеры пинга, написанного как с использованием WinAPI так и с использованием компонентов Indy.

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;

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

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

Использование Indy

Те, кто не знакомы с практикой программирования с использованием Windows API, могут воспользоваться встроенными в Delphi компонентами для работы с сетью. В частности, для реализации пинга на уровне объектно-ориентированного программирования воспользуемся компонентом >Для этого создадим сначала на пустой форме экземпляр класса TIdICMPClient, перетащив его с палитры компонентов Indy Clients. Затем поместим на форму стандартную кнопку (TButton) и в ее реакции на нажатие мышкой запишем код:

И не забудем выставить соответствующий интервал ожидания ответа, по завершении которого (или при получении данных от пингуемого) вызывается обработчик:

TidIcmpClient.OnReply (Sender:TComponent; const AReplyStatus:TReplyStatus);

— в котором мы реализуем вывод данных пинга на экран:

procedure TForm1.IdIcmpClient1Reply (ASender: TComponent;
const AReplyStatus: TReplyStatus);
begin
ListBox1.Items.Add (‘Reply:’+IntToStr (AReplyStatus.MsRoundTripTime));
end;

Послесловие

Конечно, для пинга удаленной машины вы всегда можете обратиться к соответствующей программе командной строки, поскольку 100% операционных систем поддерживает эту команду. Но не всегда дело ограничивается одним пингом — особенно если вы реализуете собственный интерфейс поверх IP. В таком случае вызов внешней программы при каждой проверке — слишком большая роскошь.

Кроме того, поняв, как работать с ICMP, вы сможете использовать эти возможности и в других — в том числе и «военных» — целях.

Листинг 1. Определения функций ICMP.DLL

unit icmp;
interface
uses windows;
Const
// IP_STATUS codes returned from IP APIs

IP_STATUS_BASE = 11000;
IP_SUCCESS = 0;
IP_BUF_TOO_SMALL = (IP_STATUS_BASE + 1);
IP_DEST_NET_UNREACHABLE = (IP_STATUS_BASE + 2);
IP_DEST_HOST_UNREACHABLE = (IP_STATUS_BASE + 3);
IP_DEST_PROT_UNREACHABLE = (IP_STATUS_BASE + 4);
IP_DEST_PORT_UNREACHABLE = (IP_STATUS_BASE + 5);
IP_NO_RESOURCES = (IP_STATUS_BASE + 6);
IP_BAD_OPTION = (IP_STATUS_BASE + 7);
IP_HW_ERROR = (IP_STATUS_BASE + 8);
IP_PACKET_TOO_BIG = (IP_STATUS_BASE + 9);
IP_REQ_TIMED_OUT = (IP_STATUS_BASE + 10);
IP_BAD_REQ = (IP_STATUS_BASE + 11);
IP_BAD_ROUTE = (IP_STATUS_BASE + 12);
IP_TTL_EXPIRED_TRANSIT = (IP_STATUS_BASE + 13);
IP_TTL_EXPIRED_REASSEM = (IP_STATUS_BASE + 14);
IP_PARAM_PROBLEM = (IP_STATUS_BASE + 15);
IP_SOURCE_QUENCH = (IP_STATUS_BASE + 16);
IP_OPTION_TOO_BIG = (IP_STATUS_BASE + 17);
IP_BAD_DESTINATION = (IP_STATUS_BASE + 18);

// The next group are status codes passed up on status indications to
// transport layer protocols.
IP_ADDR_DELETED = (IP_STATUS_BASE + 19);
IP_SPEC_MTU_CHANGE = (IP_STATUS_BASE + 20);
IP_MTU_CHANGE = (IP_STATUS_BASE + 21);
IP_UNLOAD = (IP_STATUS_BASE + 22);
IP_GENERAL_FAILURE = (IP_STATUS_BASE + 50);
MAX_IP_STATUS = IP_GENERAL_FAILURE;
IP_PENDING = (IP_STATUS_BASE + 255);

// Values used in the IP header Flags field.
IP_FLAG_DF = $2; // Don’t fragment this packet.

// Supported IP Option Types.
// These types define the options which may be used in the OptionsData field
// of the ip_option_information structure. See RFC 791 for a complete
// description of each.
IP_OPT_EOL = 0; // End of list option
IP_OPT_NOP = 1; // No operation
IP_OPT_SECURITY = $82; // Security option
IP_OPT_LSRR = $83; // Loose source route
IP_OPT_SSRR = $89; // Strict source route
IP_OPT_RR = $7; // Record route
IP_OPT_TS = $44; // Timestamp
IP_OPT_S >

MAX_OPT_SIZE = 40; // Maximum length of IP options in bytes


TIPAddr=integer; // An IP address.
TIPMask=integer; // An IP subnet mask.
TIP_STATUS=Integer; // Status code returned from IP APIs.

POption_Information=^TOption_Information;
TOption_Information=record
Ttl:byte; // Time To Live
Tos:byte; // Type Of Service
Flags:byte; // IP header flags
OptionsSize:byte; // Size in bytes of options data
OptionsData:pointer; // Pointer to options data
end;
Picmp_echo_reply=^Ticmp_echo_reply;
Ticmp_echo_reply=record
Address:TipAddr; // Replying address
Status:integer; // Reply IP_STATUS
RoundTripTime:integer; // RTT in milliseconds
DataSize:word; // Reply data size in bytes
Reserved:word; // Reserved for system use
Data:pointer; // Pointer to the reply data
Options:Toption_Information; // Reply options
end;
TsmICMP_Echo_Reply=record
Address:TipAddr; // Replying address
Status:integer; // Reply IP_STATUS
RoundTripTime:integer; // RTT in milliseconds
DataSize:word; // Reply data size in bytes
Reserved:word; // Reserved for system use
DataPtr:pointer; // Pointer to the reply data
Options:Toption_Information; // Reply options
Data: array [0..255] of Char;
end;

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;
Implementation
function IcmpCreateFile; external ‘Icmp.Dll’;
function IcmpCloseHandle; external ‘Icmp.Dll’;
Function IcmpSendEcho; external ‘Icmp.Dll’;
end.

Листинг 2. Процедура «пинга»

unit pingModule;
interface
uses icmp, Windows;
const
INADDR_NONE: integer = -1;
procedure Ping (const Address, EchoString: PChar;var PingReply: TsmICMP_Echo_Reply;
const PingTimeout: Integer = 500);
function PingStatusToStr (StatusCode: integer): string;
function inet_addr (IPAddress: PChar): TipAddr; StdCall;
implementation
uses Dialogs, SysUtils;
procedure Ping (const Address, EchoString: PChar;
var PingReply: TsmICMP_Echo_Reply;
const PingTimeout: Integer = 500);
var
IPAddress: TipAddr;
ICMPPort: THandle;
begin
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;

function PingStatusToStr (StatusCode: integer): string;
begin
case (StatusCode) of
IP_SUCCESS: Result:= ‘IP_SUCCESS’;
IP_BUF_TOO_SMALL: Result:= ‘IP_BUF_TOO_SMALL’;
IP_DEST_NET_UNREACHABLE: Result:= ‘IP_DEST_NET_UNREACHABLE’;
IP_DEST_HOST_UNREACHABLE: Result:= ‘IP_DEST_HOST_UNREACHABLE’;
IP_DEST_PROT_UNREACHABLE: Result:= ‘IP_DEST_PROT_UNREACHABLE’;
IP_DEST_PORT_UNREACHABLE: Result:= ‘IP_DEST_PORT_UNREACHABLE’;
IP_NO_RESOURCES: Result:= ‘IP_NO_RESOURCES’;
IP_BAD_OPTION: Result:= ‘IP_BAD_OPTION’;
IP_HW_ERROR: Result:= ‘IP_HW_ERROR’;
IP_PACKET_TOO_BIG: Result:= ‘IP_PACKET_TOO_BIG’;
IP_REQ_TIMED_OUT: Result:= ‘IP_REQ_TIMED_OUT’;
IP_BAD_REQ: Result:= ‘IP_BAD_REQ’;
IP_BAD_ROUTE: Result:= ‘IP_BAD_ROUTE’;
IP_TTL_EXPIRED_TRANSIT: Result:= ‘IP_TTL_EXPIRED_TRANSIT’;
IP_TTL_EXPIRED_REASSEM: Result:= ‘IP_TTL_EXPIRED_REASSEM’;
IP_PARAM_PROBLEM: Result:= ‘IP_PARAM_PROBLEM’;
IP_SOURCE_QUENCH: Result:= ‘IP_SOURCE_QUENCH’;
IP_OPTION_TOO_BIG: Result:= ‘IP_OPTION_TOO_BIG’;
IP_BAD_DESTINATION: Result:= ‘IP_BAD_DESTINATION’;
IP_ADDR_DELETED: Result:= ‘IP_ADDR_DELETED’;
IP_SPEC_MTU_CHANGE: Result:= ‘IP_SPEC_MTU_CHANGE’;
IP_MTU_CHANGE: Result:= ‘IP_MTU_CHANGE’;
IP_UNLOAD: Result:= ‘IP_UNLOAD’;
IP_GENERAL_FAILURE: Result:= ‘IP_GENERAL_FAILURE’;
else
Result:= ‘ ‘;
end;
end;

function inet_addr; external ‘WSock32.Dll’;

Листинг 3. Демонстрация пингов

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdRawBase, IdRawClient,
IdIcmpClient, StdCtrls, IdUDPBase, IdUDPClient, IdSNTP;

type
TForm1 = class (TForm)
Button1: TButton;
ListBox1: TListBox;
IdIcmpClient1: TIdIcmpClient;
IdSNTP1: TIdSNTP;
procedure Button1Click (Sender: TObject);
procedure IdIcmpClient1Reply (ASender: TComponent;
const AReplyStatus: TReplyStatus);
private

public

end;

var
Form1: TForm1;

implementation
uses pingModule,icmp;

Ping своими руками

Теория

Команда ping служит для принудительного вызова ответа конкретной машины. Для этого используется дейтаграмма ECHO_REQUEST протокола ICMP. Это протокол низкого уровня, который не требует наличия серверных процессов на зондируемой машине; это хороший способ убедится в том, что питание машины включено и IP находится в поднятом состоянии. Успешный результат использования команды ping вовсе не обязательно означает, что выполняются какие-то сервисные программы высокого уровня.

Ping — хорошее средство проверки правильности конфигурации сети, поскольку в выполнении этой команды участвуют система маршрутизации, схемы разрешения адресов и сетевые шлюзы. Если данная команда не работает — можете быть совершенно уверены, что более сложные средства тем более не функционируют. Несмотря на свою простоту, ping — одна из главных рабочих лошадок, использующихся при отладке сетей.

Практика

Для практической реализации, как всегда, можно использовать несколько подходов. Первый из них — использование низкоуровневых функций API (к примеру, встроенных в библиотеку ICMP.DLL). Второй — использование высокоуровневых компонентов (к примеру, Indy IdICMPClient).

И у первого, и у второго способа есть свои позитивные и негативные моменты. Так, при использовании функций API откомпилированный код будет иметь гораздо меньшие размеры, нежели при использовании высокоуровневых компонентов,- да и производительность его будет выше (например, при одновременном пинге одной подсети с использованием потоков).

С другой стороны, компоненты можно использовать, имея только отдаленное представление о работе с протоколом ICMP, а также об использовании Windows API. Но, в то же время, компоненты порождают неоправданно большой исполняемый код, да и производительность в этом случае ниже. К счастью, сегодня разработчиками процессоров и памяти почти стерта грань между производительностью кода, написанного с использованием Windows API, и кода, написанного с использованием средств более высокого уровня абстракции (в нашем случае — компонентов Delphi).

На всякий случай приведем примеры пинга, написанного как с использованием WinAPI так и с использованием компонентов Indy.

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;

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

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

Использование Indy

Те, кто не знакомы с практикой программирования с использованием Windows API, могут воспользоваться встроенными в Delphi компонентами для работы с сетью. В частности, для реализации пинга на уровне объектно-ориентированного программирования воспользуемся компонентом IdICMPClient из состава Indy.

Для этого создадим сначала на пустой форме экземпляр класса TIdICMPClient, перетащив его с палитры компонентов Indy Clients. Затем поместим на форму стандартную кнопку (TButton) и в ее реакции на нажатие мышкой запишем код:

И не забудем выставить соответствующий интервал ожидания ответа, по завершении которого (или при получении данных от пингуемого) вызывается обработчик:

TidIcmpClient.OnReply (Sender:TComponent; const AReplyStatus:TReplyStatus);

— в котором мы реализуем вывод данных пинга на экран:

procedure TForm1.IdIcmpClient1Reply (ASender: TComponent;
const AReplyStatus: TReplyStatus);
begin
ListBox1.Items.Add (‘Reply:’+IntToStr (AReplyStatus.MsRoundTripTime));
end;

Послесловие

Конечно, для пинга удаленной машины вы всегда можете обратиться к соответствующей программе командной строки, поскольку 100% операционных систем поддерживает эту команду. Но не всегда дело ограничивается одним пингом — особенно если вы реализуете собственный интерфейс поверх IP. В таком случае вызов внешней программы при каждой проверке — слишком большая роскошь.

Кроме того, поняв, как работать с ICMP, вы сможете использовать эти возможности и в других — в том числе и «военных» — целях.

Листинг 1. Определения функций ICMP.DLL

unit icmp;
interface
uses windows;
Const
// IP_STATUS codes returned from IP APIs

IP_STATUS_BASE = 11000;
IP_SUCCESS = 0;
IP_BUF_TOO_SMALL = (IP_STATUS_BASE + 1);
IP_DEST_NET_UNREACHABLE = (IP_STATUS_BASE + 2);
IP_DEST_HOST_UNREACHABLE = (IP_STATUS_BASE + 3);
IP_DEST_PROT_UNREACHABLE = (IP_STATUS_BASE + 4);
IP_DEST_PORT_UNREACHABLE = (IP_STATUS_BASE + 5);
IP_NO_RESOURCES = (IP_STATUS_BASE + 6);
IP_BAD_OPTION = (IP_STATUS_BASE + 7);
IP_HW_ERROR = (IP_STATUS_BASE + 8);
IP_PACKET_TOO_BIG = (IP_STATUS_BASE + 9);
IP_REQ_TIMED_OUT = (IP_STATUS_BASE + 10);
IP_BAD_REQ = (IP_STATUS_BASE + 11);
IP_BAD_ROUTE = (IP_STATUS_BASE + 12);
IP_TTL_EXPIRED_TRANSIT = (IP_STATUS_BASE + 13);
IP_TTL_EXPIRED_REASSEM = (IP_STATUS_BASE + 14);
IP_PARAM_PROBLEM = (IP_STATUS_BASE + 15);
IP_SOURCE_QUENCH = (IP_STATUS_BASE + 16);
IP_OPTION_TOO_BIG = (IP_STATUS_BASE + 17);
IP_BAD_DESTINATION = (IP_STATUS_BASE + 18);

// The next group are status codes passed up on status indications to
// transport layer protocols.
IP_ADDR_DELETED = (IP_STATUS_BASE + 19);
IP_SPEC_MTU_CHANGE = (IP_STATUS_BASE + 20);
IP_MTU_CHANGE = (IP_STATUS_BASE + 21);
IP_UNLOAD = (IP_STATUS_BASE + 22);
IP_GENERAL_FAILURE = (IP_STATUS_BASE + 50);
MAX_IP_STATUS = IP_GENERAL_FAILURE;
IP_PENDING = (IP_STATUS_BASE + 255);

// Values used in the IP header Flags field.
IP_FLAG_DF = $2; // Don’t fragment this packet.

// Supported IP Option Types.
// These types define the options which may be used in the OptionsData field
// of the ip_option_information structure. See RFC 791 for a complete
// description of each.
IP_OPT_EOL = 0; // End of list option
IP_OPT_NOP = 1; // No operation
IP_OPT_SECURITY = $82; // Security option
IP_OPT_LSRR = $83; // Loose source route
IP_OPT_SSRR = $89; // Strict source route
IP_OPT_RR = $7; // Record route
IP_OPT_TS = $44; // Timestamp
IP_OPT_S >

MAX_OPT_SIZE = 40; // Maximum length of IP options in bytes

TIPAddr=integer; // An IP address.
TIPMask=integer; // An IP subnet mask.
TIP_STATUS=Integer; // Status code returned from IP APIs.

POption_Information=^TOption_Information;
TOption_Information=record
Ttl:byte; // Time To Live
Tos:byte; // Type Of Service
Flags:byte; // IP header flags
OptionsSize:byte; // Size in bytes of options data
OptionsData:pointer; // Pointer to options data
end;
Picmp_echo_reply=^Ticmp_echo_reply;
Ticmp_echo_reply=record
Address:TipAddr; // Replying address
Status:integer; // Reply IP_STATUS
RoundTripTime:integer; // RTT in milliseconds
DataSize:word; // Reply data size in bytes
Reserved:word; // Reserved for system use
Data:pointer; // Pointer to the reply data
Options:Toption_Information; // Reply options
end;
TsmICMP_Echo_Reply=record
Address:TipAddr; // Replying address
Status:integer; // Reply IP_STATUS
RoundTripTime:integer; // RTT in milliseconds
DataSize:word; // Reply data size in bytes
Reserved:word; // Reserved for system use
DataPtr:pointer; // Pointer to the reply data
Options:Toption_Information; // Reply options
Data: array [0..255] of Char;
end;

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;
Implementation
function IcmpCreateFile; external ‘Icmp.Dll’;
function IcmpCloseHandle; external ‘Icmp.Dll’;
Function IcmpSendEcho; external ‘Icmp.Dll’;
end.

Листинг 2. Процедура «пинга»

unit pingModule;
interface
uses icmp, Windows;
const
INADDR_NONE: integer = -1;
procedure Ping (const Address, EchoString: PChar;var PingReply: TsmICMP_Echo_Reply;
const PingTimeout: Integer = 500);
function PingStatusToStr (StatusCode: integer): string;
function inet_addr (IPAddress: PChar): TipAddr; StdCall;
implementation
uses Dialogs, SysUtils;
procedure Ping (const Address, EchoString: PChar;
var PingReply: TsmICMP_Echo_Reply;
const PingTimeout: Integer = 500);
var
IPAddress: TipAddr;
ICMPPort: THandle;
begin
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;

function PingStatusToStr (StatusCode: integer): string;
begin
case (StatusCode) of
IP_SUCCESS: Result:= ‘IP_SUCCESS’;
IP_BUF_TOO_SMALL: Result:= ‘IP_BUF_TOO_SMALL’;
IP_DEST_NET_UNREACHABLE: Result:= ‘IP_DEST_NET_UNREACHABLE’;
IP_DEST_HOST_UNREACHABLE: Result:= ‘IP_DEST_HOST_UNREACHABLE’;
IP_DEST_PROT_UNREACHABLE: Result:= ‘IP_DEST_PROT_UNREACHABLE’;
IP_DEST_PORT_UNREACHABLE: Result:= ‘IP_DEST_PORT_UNREACHABLE’;
IP_NO_RESOURCES: Result:= ‘IP_NO_RESOURCES’;
IP_BAD_OPTION: Result:= ‘IP_BAD_OPTION’;
IP_HW_ERROR: Result:= ‘IP_HW_ERROR’;
IP_PACKET_TOO_BIG: Result:= ‘IP_PACKET_TOO_BIG’;
IP_REQ_TIMED_OUT: Result:= ‘IP_REQ_TIMED_OUT’;
IP_BAD_REQ: Result:= ‘IP_BAD_REQ’;
IP_BAD_ROUTE: Result:= ‘IP_BAD_ROUTE’;
IP_TTL_EXPIRED_TRANSIT: Result:= ‘IP_TTL_EXPIRED_TRANSIT’;
IP_TTL_EXPIRED_REASSEM: Result:= ‘IP_TTL_EXPIRED_REASSEM’;
IP_PARAM_PROBLEM: Result:= ‘IP_PARAM_PROBLEM’;
IP_SOURCE_QUENCH: Result:= ‘IP_SOURCE_QUENCH’;
IP_OPTION_TOO_BIG: Result:= ‘IP_OPTION_TOO_BIG’;
IP_BAD_DESTINATION: Result:= ‘IP_BAD_DESTINATION’;
IP_ADDR_DELETED: Result:= ‘IP_ADDR_DELETED’;
IP_SPEC_MTU_CHANGE: Result:= ‘IP_SPEC_MTU_CHANGE’;
IP_MTU_CHANGE: Result:= ‘IP_MTU_CHANGE’;
IP_UNLOAD: Result:= ‘IP_UNLOAD’;
IP_GENERAL_FAILURE: Result:= ‘IP_GENERAL_FAILURE’;
else
Result:= ‘ ‘;
end;
end;

function inet_addr; external ‘WSock32.Dll’;

Листинг 3. Демонстрация пингов

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdRawBase, IdRawClient,
IdIcmpClient, StdCtrls, IdUDPBase, IdUDPClient, IdSNTP;

type
TForm1 = class (TForm)
Button1: TButton;
ListBox1: TListBox;
IdIcmpClient1: TIdIcmpClient;
IdSNTP1: TIdSNTP;
procedure Button1Click (Sender: TObject);
procedure IdIcmpClient1Reply (ASender: TComponent;
const AReplyStatus: TReplyStatus);
private

public

end;

procedure TForm1.Button1Click (Sender: TObject);
var Reply:TsmICMP_Echo_Reply;
begin
Self. ;
Self. >Self.IdIcmpClient1.Ping;
Ping (‘127.0.0.1’,nil,Reply,5000);
ListBox1.Items.Add (‘RawReply:’+IntToStr (Reply.RoundTripTime));
end;

procedure TForm1.IdIcmpClient1Reply (ASender: TComponent;
const AReplyStatus: TReplyStatus);
begin
ListBox1.Items.Add (‘Reply:’+IntToStr (AReplyStatus.MsRoundTripTime));
end;

Автор: Михаил Продан
Источник: www.cpp.com.ua

Комментарии
Последние статьи: Программирование под ОС / Pascal — Delphi /


Сегодня поговорим о шрифтах, и о том, каким образом работать с ними на Win API. Нам потребуется переменная типа HFONT. Изменить стиль шрифта можно у любого компонента, я покажу это на примере кнопки. подробнее

Таймер — вещь в хозяйстве очень полезная. Если некое действие нужно повторять с определенной периодичностью, то таймер, это как раз то, что нужно. подробнее

Мы уже знакомы с системным таймером, сегодня познакомимся с мультимедийным, основное отличие которого, более высокая скорость (точность) работы. подробнее

Сегодня наша программа научится работать с CheckBoxами. CheckBox можно представить как флаг, который можно установить или сбросить, и в зависимости от его состояния выполнять определенные действия. подробнее

В прошлый раз мы сделали несколько радио-кнопок, которые автоматически объединялись в одну группу. Сейчас рассмотрим, как создавать несколько независимых групп радио-кнопок. подробнее

Пингуем (ping) под delphi

Ну блин извиняйте, мне нужен результат, вот это главное. Постараюсь в следующий раз быть более детальным.

Но в любом случае, неужели никому никогда не надо было реализовать такую возможность?

антивариант че то — может кто нить исходник поможет перелопатить?
Код: Выделить всё unit IpPing;

Uses
Windows, Messages, SysUtils, Variants, Classes, Crt, WinSock;

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;

ip_repl_info = packed record
type_err : boolean; //Тип ответа, True -Нет ошибки
// False-Есть ошибка
err_mes : string; // код ошибки
err_code : integer;
time_rep : string; // время отклика
end;

PIPINFO = ^ip_option_information;
// PVO >
function IcmpCreateFile() : THandle; stdcall; external ‘ICMP.DLL’ name ‘IcmpCreateFile’;
function IcmpCloseHandle(IcmpHandle : THandle) : BOOL; 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’;

// Функция посылает ping по указанному адресу и можно получить
// различные результаты
function iping (ipadress : Pchar) : ip_repl_info;

function iping(ipadress : PChar) : ip_repl_info;
var
hIP : THandle;
pingBuffer : array [0..31] of Char;
pIpe : ^icmp_echo_reply;
pHostEn : PHostEnt;
wVersionRequested : WORD;
lwsaData : WSAData;
error : DWORD;
destAddress : In_Addr;
begin

// Создаем handle
hIP := IcmpCreateFile();

GetMem( pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer));
pIpe.Data := @pingBuffer;//@pingBuffer;
pIpe.DataSize := sizeof(pingBuffer);

wVersionRequested := MakeWord(1,1);
error := WSAStartup(wVersionRequested,lwsaData);
if (error <> 0) then
begin
iping.err_mes := ‘ошибка при подготовки пакета Код: ‘+IntToStr(error);
iping.err_code := error;
iping.type_err := False;
< Memo1.SetTextBuf('Error in call to '+
‘WSAStartup().’);
Memo1.Lines.Add(‘Error code: ‘+IntToStr(error));>
Exit;
end;

pHostEn := gethostbyname(ipadress);
error := GetLastError();
if (error <> 0) then
begin
iping.err_mes := ‘Неверно определен хост код: ‘+IntToStr(error);
iping.err_code := error;
iping.type_err := False;
< Memo1.SetTextBuf('Error in call to'+
‘gethostbyname().’);
Memo1.Lines.Add(‘Error code: ‘+IntToStr(error));>
Exit;
end;

// Посылаем ping-пакет
< Memo1.Lines.Add('Pinging ' +
pHostEn^.h_name+’ [‘+
inet_ntoa(destAddress)+’] ‘+
‘ with ‘+
IntToStr(sizeof(pingBuffer)) +
‘ bytes of data:’);>

IcmpSendEcho(hIP,
destAddress.S_addr,
@pingBuffer,
sizeof(pingBuffer),
Nil,
pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer),
5000);

error := GetLastError();
if (error <> 0) then
begin
iping.err_mes := ‘Ошибка в отправке пакета: ‘+IntToStr(error);
iping.err_code := error;
iping.type_err := False;
< Memo1.SetTextBuf('Error in call to '+
‘IcmpSendEcho()’);
Memo1.Lines.Add(‘Error code: ‘+IntToStr(error));>
Exit;
end;

// Смотрим некоторые из вернувшихся данных
iping.type_err := True;
iping.time_rep := IntToStr(pIpe.RTTime);
// iping := IntToStr(pIpe.RTTime);
< Memo1.Lines.Add('Reply from '+
IntToStr(LoByte(LoWord(pIpe^.Address)))+’.’+
IntToStr(HiByte(LoWord(pIpe^.Address)))+’.’+
IntToStr(LoByte(HiWord(pIpe^.Address)))+’.’+
IntToStr(HiByte(HiWord(pIpe^.Address))));
Memo1.Lines.Add(‘Reply time: ‘+IntToStr(pIpe.RTTime)+’ ms’);>

IcmpCloseHandle(hIP);
WSACleanup();
FreeMem(pIpe);
end;
end.

есть три варианта
1. использовать виндовую icmp.dll
2. использовать компонент ICMP (в сунапсе или инди)
3. делать полностью самому (похоже эта задача не стоит)

исходник — это использование виндовой dll
почитать можно тут

А у меня вдогонку тоже вопрос, почти в тему, может кто знает:

Как и какими средствами (библиотеками/модулями FPC) запрашивать информацию для DHCP?

Честно говоря, даже представления не имею какими протоколами и как это все делается.

хм. что значит для ? может быть у DHCP-сервера? или пишется сам DHCP-сервер?

алгоритм прост — выбирается любой пункт на Ваш вкус:
1. смотрится инди или сунапс на предмет наличия компоненто нужного плана
2. смотрится интернет на предмет наличия стороннего компонента
3. смотрится рекомендация DHCP и по ней реализуются нужные методы
4. ставится сниффер, ловится трафик, анализируется и потом повторяется (это совсем для извращенцев)

Re: Выполнить PING средствами fpc

Re: Выполнить PING средствами fpc

Толик писал(а): антивариант че то — может кто нить исходник поможет перелопатить?
Код: Выделить всё unit IpPing;

Uses
Windows, Messages, SysUtils, Variants, Classes, Crt, WinSock;

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;

ip_repl_info = packed record
type_err : boolean; //Тип ответа, True -Нет ошибки
// False-Есть ошибка
err_mes : string; // код ошибки
err_code : integer;
time_rep : string; // время отклика
end;

PIPINFO = ^ip_option_information;
// PVO >
function IcmpCreateFile() : THandle; stdcall; external ‘ICMP.DLL’ name ‘IcmpCreateFile’;
function IcmpCloseHandle(IcmpHandle : THandle) : BOOL; 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’;

// Функция посылает ping по указанному адресу и можно получить
// различные результаты
function iping (ipadress : Pchar) : ip_repl_info;

function iping(ipadress : PChar) : ip_repl_info;
var
hIP : THandle;
pingBuffer : array [0..31] of Char;
pIpe : ^icmp_echo_reply;
pHostEn : PHostEnt;
wVersionRequested : WORD;
lwsaData : WSAData;
error : DWORD;
destAddress : In_Addr;
begin

// Создаем handle
hIP := IcmpCreateFile();

GetMem( pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer));
pIpe.Data := @pingBuffer;//@pingBuffer;
pIpe.DataSize := sizeof(pingBuffer);

wVersionRequested := MakeWord(1,1);
error := WSAStartup(wVersionRequested,lwsaData);
if (error <> 0) then
begin
iping.err_mes := ‘ошибка при подготовки пакета Код: ‘+IntToStr(error);
iping.err_code := error;
iping.type_err := False;
< Memo1.SetTextBuf('Error in call to '+
‘WSAStartup().’);
Memo1.Lines.Add(‘Error code: ‘+IntToStr(error));>
Exit;
end;

pHostEn := gethostbyname(ipadress);
error := GetLastError();
if (error <> 0) then
begin
iping.err_mes := ‘Неверно определен хост код: ‘+IntToStr(error);
iping.err_code := error;
iping.type_err := False;
< Memo1.SetTextBuf('Error in call to'+
‘gethostbyname().’);
Memo1.Lines.Add(‘Error code: ‘+IntToStr(error));>
Exit;
end;

// Посылаем ping-пакет
< Memo1.Lines.Add('Pinging ' +
pHostEn^.h_name+’ [‘+
inet_ntoa(destAddress)+’] ‘+
‘ with ‘+
IntToStr(sizeof(pingBuffer)) +
‘ bytes of data:’);>

IcmpSendEcho(hIP,
destAddress.S_addr,
@pingBuffer,
sizeof(pingBuffer),
Nil,
pIpe,
sizeof(icmp_echo_reply) + sizeof(pingBuffer),
5000);

error := GetLastError();
if (error <> 0) then
begin
iping.err_mes := ‘Ошибка в отправке пакета: ‘+IntToStr(error);
iping.err_code := error;
iping.type_err := False;
< Memo1.SetTextBuf('Error in call to '+
‘IcmpSendEcho()’);
Memo1.Lines.Add(‘Error code: ‘+IntToStr(error));>
Exit;
end;

// Смотрим некоторые из вернувшихся данных
iping.type_err := True;
iping.time_rep := IntToStr(pIpe.RTTime);
// iping := IntToStr(pIpe.RTTime);
< Memo1.Lines.Add('Reply from '+
IntToStr(LoByte(LoWord(pIpe^.Address)))+’.’+
IntToStr(HiByte(LoWord(pIpe^.Address)))+’.’+
IntToStr(LoByte(HiWord(pIpe^.Address)))+’.’+
IntToStr(HiByte(HiWord(pIpe^.Address))));
Memo1.Lines.Add(‘Reply time: ‘+IntToStr(pIpe.RTTime)+’ ms’);>

IcmpCloseHandle(hIP);
WSACleanup();
FreeMem(pIpe);
end;
end.

Delphi ICMP Sample Source Code

Network Component provides an easy-to-use development interface to a variety of IP protocols. By using Network Component, you can very easily create or enhance applications with network features.

Network Component features the following: DNS, FTP, HTTP, HTTPs, ICMP Ping, IP-to-Country, MSN, NTP, RSH, SCP, SFTP, SNMP v1/v2c (Get, GetNext, Set), SNMP Traps, SNMP MIB, SSH, TCP, Telnet, TFTP, UDP, Telnet, Wake-On-LAN and more.

Network Component can be well integrated into any development platform that supports ActiveX objects.

Step 1: Download and install the Network Component

Download Network Component from the ActiveXperts Download Site and start the installation. The installation guides you through the installation process.

Step 2: Create a new Delphi Project

Launch Borland Delphi from the Start menu. Choose ‘New’ from the ‘File’ menu and select your preferred kind of application, for instance: ‘VCL Forms Application — Delphi for Win32’. A new Form is displayed in the workspace.

Step 3: Refer to the Network Component Library and create the objects

Now that a new project has been created, you must add a reference to Network Component in the project to be able to use the Network Component object. To do so, choose ‘Import Component. ‘ from the ‘Component’ menu. The Import Components’ dialog appears. Select ‘Import a Type Library’:

(Click on the picture to enlarge)

In the ‘Registered Type Libraries’ page, select ‘Network Component 4.4 Type Library’ and click ‘Next’:

(Click on the picture to enlarge)

In the ‘Components’ page, leave all fields default and click ‘Next’:

(Click on the picture to enlarge)

In the ‘Install’ page, select ‘Create Unit’ and click ‘Next’:

(Click on the picture to enlarge)

The interface code is generated now and is shown in the AxNetwork_TLB tab of the project.

Step 4: Declare and create the object

From the Project Manager, open Unit1.bas and add the AxNetwork_TLB to the ‘Uses’ statement to refer to the Network Component library:

(Click on the picture to enlarge)

In the ‘private’ or ‘public’ section, declare the following objects:

You can now create the objects, for instance in the ‘FormCreate’ function:

Илон Маск рекомендует:  padding-bottom в CSS
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL