rzaripov.kz

Пинг-утилита на Delphi с многопоточностью

Многопоточная пинг-утилита на Delphi позволяет одновременно проверять доступность сетевых узлов и измерять задержку до них. В последовательной реализации каждый адрес блокирует интерфейс на время ожидания ответа, поэтому много удалённых хостов превращают проверку в долгий процесс. Параллельный вариант разделяет эти ожидания между рабочими потоками и возвращает результаты по мере их поступления.

Практичная конструкция состоит из независимого сетевого модуля, планировщика задач, накопителя результатов и слоя вывода. Сетевой модуль отвечает за конкретный способ отправки ICMP-пакетов, планировщик ограничивает число одновременно работающих целей, а результаты передаются в поток интерфейса через очередь. Такое разделение позволяет менять платформенную реализацию и формат вывода, не переписывая основную логику проверки.

Отдельно обрабатываются разрешение имени, тайм-аут, повторные запросы и отмена работы. Именно эти детали чаще всего отличают учебный пример от утилиты, которой удобно пользоваться при диагностике сети из Алматы или любого другого города.

Сетевой протокол и модель измерений

Базовый механизм диагностики использует сообщения ICMP типа Echo Request и Echo Reply. Отправленный пакет содержит идентификатор сессии, номер последовательности и необязательные данные для сверки с ответом. По разнице монотонных отметок времени вычисляется время обратного пути, а счётчик ответов показывает, какая доля запросов вернулась.

Исчезновение ответа не доказывает, что узел выключен: его мог отбросить межсетевой экран, маршрутизатор или оператор связи. Поэтому результат разумно разделять на успешный ответ, сетевой тайм-аут и ошибку разрешения адреса, не объединяя разные причины в один статус.

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

Архитектура приложения и потоков

Ядро утилиты лучше собрать как консольное приложение или отдельный модуль без прямой зависимости от VCL и FireMonkey. В нём удобно описать параметры адреса, число попыток, интервал и тайм-аут, а также результат проверки. Повторное использование такого модуля упрощает создание графической версии и мобильного приложения.

Базовые типы можно описать без привязки к компонентам интерфейса:

type
  TProbeOptions = record
    Host: string;
    Count: Integer;
    TimeoutMs: Cardinal;
    IntervalMs: Integer;
  end;

  TProbeResult = record
    Host: string;
    Address: string;
    Replies: Integer;
    LastRttMs: Cardinal;
    ErrorText: string;
  end;

Для фоновой работы подходят TTask, пул потоков или собственные экземпляры TThread. Предпочтительно использовать ограниченное число рабочих задач: в современных версиях Delphi обработчики графического интерфейса получают данные через TThread.ForceQueue, поэтому потоки не обращаются к элементам формы напрямую.

Жизненный цикл задач должен зависеть от явного запроса остановки. Проверка флага отмены выполняется между пакетами и во время пауз, а отдельное ожидание сокета всегда ограничено тайм-аутом. Исключения перехватываются внутри рабочей процедуры, и после завершения освобождаются ресурсы. Это предотвращает зависание программы при разрыве связи или ошибке доступа к сокету.

Выполнение ICMP-запросов

В Windows основной путь строится на функции IcmpSendEcho из IP Helper API. Она принимает числовой IPv4-адрес, необязательные данные, размер буфера и тайм-аут, а возвращает число ответов вместе с массивом структур IP_ECHO_REPLY. Буфер выделяется отдельно и обнуляется: первые четыре байта содержат счётчик ответов, после которого идут структуры с выравниванием под разрядность процесса. Обычные эхо-запросы не требуют запуска утилиты с правами администратора.

На Linux и macOS применяется отдельный модуль с сырым сокетом и протоколом ICMP. Такой сокет обычно требует root либо выделенного Linux-разрешения CAP_NET_RAW, поэтому наличие привилегий нужно проверять до запуска проверок. Ответ читается с тайм-аутом через poll или select, а длительность измеряется монотонными часами, чтобы перевод системного времени не искажал результат.

Имя узла разрешается заранее через DNS-клиент или платформенный getaddrinfo, после чего платформенный слой получает готовый адрес. Ошибки DNS учитываются отдельно от недоступности уже разрешённого адреса. При поддержке IPv6 протокол и формат адреса выбираются явно, чтобы не передавать IPv4-значение в функцию, ожидающую IPv6.

Параллельные проверки узлов

Планировщик задаёт верхнюю границу параллелизма независимо от количества целей в списке. Один рабочий поток обрабатывает один адрес, а заданное число пакетов отправляет последовательно с нужной паузой; одновременно другие потоки занимаются остальными адресами. Такой вариант сохраняет порядок результатов внутри каждой цели и не создаёт тысячу потоков ради тысячи строк входных данных.

Разрешение DNS лучше вынести в отдельный ограниченный пул: ожидание сервера имён не должно занимать ресурсы, предназначенные для приёма ICMP-ответов. После преобразования адресов планировщик запускает только сетевые проверки, поэтому длительные задержки имен сервера не смешиваются с задержкой маршрута.

Состояние общей коллекции защищают синхронизацией либо передают результат по очереди без конкурентной записи. Порядок строк восстанавливают по исходному индексу цели, а готовность завершения определяют по счётчику задач, а не по факту показа последнего ответа. Эти меры снижают риск гонок и потери результатов при быстром завершении программы.

Результаты, интерфейс и управление

Для каждого адреса сохраняют число отправленных и принятых пакетов, последнее или среднее время ответа, адрес узла и категорию ошибки. Коды состояния Windows и признаки истечения времени POSIX переводят в понятные статусы, не смешивая их с исключением сокета. Значение TTL добавляют только тогда, когда оно реально доступно выбранной реализации.

Графический слой FireMonkey или VCL получает пакет обновлений из очереди и меняет прогресс уже в основном потоке. Так интерфейс остаётся отзывчивым, а строки результатов могут сортироваться по задержке, адресу или числу потерь. Для консольного варианта удобно накапливать завершённые строки и выводить их в исходном порядке либо сразу по завершении отдельной цели.

Параметры командной строки задают список или диапазон адресов, количество запросов, паузу, тайм-аут, предел потоков и формат вывода. Значения проверяются на допустимые диапазоны до запуска потоков, а пользовательский ввод не передаётся командной оболочке. Команда остановки должна завершать ожидания и освобождать сокеты независимо от текущего результата.

Проверка качества и безопасность

Автоматические проверки охватывают локальный адрес, шлюз, внешний узел, неверное имя и недоступный маршрут. Отдельно воспроизводятся потеря части ответов, нулевая задержка и превышение тайм-аута. IPv4 и IPv6 проверяются независимо, чтобы ошибка одного протокола не скрывала работоспособность другого.

Нагрузочные тесты измеряют расход памяти, число активных потоков и время завершения при десятках и сотнях целей. Особое внимание уделяют гонкам при одновременном обновлении интерфейса, взаимным блокировкам и утечкам сокетов. Повторные запуски с включённым анализатором помогают убедиться, что потоки действительно завершились, а результаты не зависают в очереди.

Привилегии запрашивают только там, где они обязательны для конкретного сокета, а собранные данные не содержат лишней полезной нагрузки. Пинг проверяет доступность узла на сетевом уровне, но не подтверждает работу приложения или базы данных за ним. Для такой проверки используют отдельный HTTP-запрос с ожидаемым ответом.

Различия платформ и практическое применение

Настольные версии Delphi для Windows, Linux и macOS могут использовать разные сетевые модули при общей модели потоков. Мобильные ограничения строже: приложение на Kotlin обычно не получает прямой доступ к сырым ICMP-сокетам, а Swift предоставляет сетевые API без возможности произвольно отправлять такие пакеты. Поэтому для Android и iOS практичнее проверять достижимость через разрешённый транспорт, а точные ICMP-измерения оставлять настольной версии или согласованному серверному компоненту.

Такой подход хорошо согласуется с кроссплатформенной разработкой, представленной на сайте разработчика. В профессиональном профиле Равиля Зарипова собраны проекты на Delphi, FireMonkey, Kotlin и Swift, а также серверные решения на PHP и работа с базами данных. Этот опыт полезен для выбора безопасной архитектуры, которая не переносит ограничения одной платформы на все остальные.

Платформа Механизм проверки Ограничение
Windows IcmpSendEcho Обычные эхо-запросы не требуют повышения прав
Linux Сырой ICMP-сокет Обычно нужны root или CAP_NET_RAW
macOS Сырой ICMP-сокет Обычно нужны права администратора
Android HTTP или TCP-проверка в Kotlin Прямой ICMP обычному приложению недоступен
iOS HTTP или TCP-проверка в Swift Произвольные ICMP-пакеты недоступны

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