Как проверить доступность сетевого узла и выполнить ping из 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

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

Почему стандартный ping через WScript.Shell возвращает неверный результат

Проанализируем типичную ошибку при попытке выполнить проверку через WScript.Shell:


Процедура КнопкаВыполнитьНажатие(Кнопка)
    Адр = "80.252.128.110";
    wss = Новый COMОбъект("WScript.Shell");
    Результат = Не wss.Run("ping -w 1500 -n 1 " + Адр, 0, Истина);
КонецПроцедуры

Выясним причину, почему переменная Результат может принимать значение Истина, даже если интернет-канал на роутере фактически отключен (например, вынута SIM-карта или заблокирован счет провайдера):

  1. Особенности кодов возврата утилиты ping.exe: процесс в Windows завершается с кодом 0 (успех) не только тогда, когда получен ответ от целевого узла, но и в случае, когда локальный шлюз (роутер) возвращает ICMP-сообщение «Destination host unreachable» (узел назначения недоступен). Физическая связь между компьютером и роутером сохраняется, роутер отвечает сетевому стеку компьютера об ошибке маршрутизации, и ОС считает команду успешно отработавшей.
  2. Код ошибки 1: возвращается утилитой только при полном таймауте пакета или при отсутствии физического линка на сетевой карте самого компьютера (когда выдернут LAN-кабель).

Способ 1. Использование WMI-класса Win32_PingStatus через COM

Наиболее точным и быстрым способом в среде Windows является прямое обращение к службе инструментария управления Windows (WMI) через системный класс Win32_PingStatus. Этот метод позволяет не только получить точный статус доставки пакета, но и считать время отклика (ResponseTime), размер пакета и значение TTL.

Посмотрим на пример универсальной экспортной функции:


// Функция проверяет доступность узла по IP-адресу или имени хоста
Функция ПроверитьДоступностьУзла(Знач IPИлиИмяХоста) Экспорт
    
    Попытка
        ЛокаторWMI = ПолучитьCOMОбъект("winmgmts:{impersonationLevel=impersonate}");
        Запрос = "SELECT StatusCode, ResponseTime FROM Win32_PingStatus WHERE Address = '" + IPИлиИмяХоста + "' AND Timeout = 1000";
        КоллекцияРезультатов = ЛокаторWMI.ExecQuery(Запрос);
    Исключение
        // Ошибка инициализации COM-объекта WMI
        Возврат Неопределено;
    КонецПопытки;
    
    Для Каждого Элемент Из КоллекцияРезультатов Цикл
        // StatusCode = 0 означает успешное получение эхо-ответа
        Если Элемент.StatusCode <> Неопределено И Элемент.StatusCode = 0 Тогда
            Возврат Истина;
        Иначе
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Ложь;
    
КонецФункции

Рассмотрим подробнее важные параметры данного запроса:

  1. Address: целевой IP-адрес или DNS-имя хоста для отправки ICMP-запроса.
  2. Timeout: максимальное время ожидания ответа в миллисекундах (в примере задано значение 1000 мс).
  3. StatusCode: код состояния ответа. Значение 0 свидетельствует об успешном ответе целевого узла (Success). Любые другие коды (например, 11003 — Host Unreachable, 11010 — Request Timed Out) говорят об отсутствии связи.

Способ 2. Выполнение проверки через MSScriptControl

Если требуется изолировать логику выполнения запроса в рамках скриптового движка VBScript, можно применить COM-объект MSScriptControl.ScriptControl.

Посмотрим на программную реализацию:


Функция ВыполнитьПингЧерезСкрипт(Знач ИмяУзла) Экспорт
    
    Попытка
        СкриптКонтрол = Новый COMОбъект("MSScriptControl.ScriptControl");
        СкриптКонтрол.Language = "vbscript";
        
        ТекстСкрипта = 
        "Function PingHost(HostName)
        |   Set objWMI = GetObject(""winmgmts:{impersonationLevel=impersonate}"")
        |   Set colPings = objWMI.ExecQuery(""SELECT StatusCode FROM Win32_PingStatus WHERE Address = '"" & HostName & ""' AND Timeout = 1000"")
        |   For Each objPing In colPings
        |       If Not IsNull(objPing.StatusCode) And objPing.StatusCode = 0 Then
        |           PingHost = True
        |           Exit Function
        |       End If
        |   Next
        |   PingHost = False
        |End Function";
        
        СкриптКонтрол.AddCode(ТекстСкрипта);
        Результат = СкриптКонтрол.Run("PingHost", ИмяУзла);
        Возврат Результат;
    Исключение
        Возврат Ложь;
    КонецПопытки;
    
КонецФункции

Обратите внимание: объект MSScriptControl.ScriptControl является 32-разрядным компонентом Windows. Если код выполняется на стороне 64-разрядного сервера 1С:Предприятия (процесс rphost) или в 64-разрядном клиенте, создание этого COM-объекта вызовет ошибку. Для серверного или кроссплатформенного кода предпочтительнее использовать штатные механизмы 1С.

Способ 3. Кроссплатформенная проверка доступности через HTTPСоединение

Если основная цель — проверить наличие фактического подключения к сети Интернет или доступность конкретного веб-сервера (а не просто прохождение ICMP-пакетов внутри локальной сети), наиболее надежным и платформонезависимым решением является объект HTTPСоединение.

Разберем реализацию проверки без использования внешних утилит и COM-объектов:


Функция ПроверитьИнтернетСоединение(Знач АдресСервера = "ya.ru", Знач Таймаут = 3) Экспорт
    
    Попытка
        // Создаем защищенное или обычное соединение с коротким таймаутом
        Соединение = Новый HTTPСоединение(АдресСервера, 443, , , , Таймаут, Новый ЗащищенноеСоединениеOpenSSL());
        Запрос = Новый HTTPЗапрос("/");
        Ответ = Соединение.Получить(Запрос);
        
        Если Ответ.КодСостояния >= 200 И Ответ.КодСостояния < 400 Тогда
            Возврат Истина;
        Иначе
            Возврат Ложь;
        КонецЕсли;
    Исключение
        // Ошибка соединения, таймаут или отсутствие сети
        Возврат Ложь;
    КонецПопытки;
    
КонецФункции

Преимущества такого подхода:

  1. Кроссплатформенность: код корректно выполняется как в среде Windows, так и в Linux.
  2. Независимость от разрядности: работает одинаково стабильно в 32- и 64-разрядных клиентах и серверах 1С.
  3. Реальная проверка канала: отправка HTTP/HTTPS-запроса к публичному DNS-серверу или веб-ресурсу подтверждает полную работоспособность сетевого стека, DNS-резолвинга и шлюза провайдера.

Способ 4. Получение сетевых настроек узла через WMI

Если в рамках задачи системного администрирования требуется не только проверить пинг, но и получить IP-адреса сетевых адаптеров или шлюзов по умолчанию удаленного компьютера, воспользуемся классом Win32_NetworkAdapterConfiguration:


Процедура ПолучитьСетевыеНастройки(Знач ИмяКомпьютера) Экспорт
    
    Попытка
        ЛокаторWMI = ПолучитьCOMОбъект("winmgmts:{impersonationLevel=impersonate}!\\" + ИмяКомпьютера + "\root\cimv2");
        Адаптеры = ЛокаторWMI.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True");
        
        Для Каждого Адаптер Из Адаптеры Цикл
            ИмяХоста = СокрЛП(Адаптер.DNSHostName);
            
            // Чтение списка IP-адресов адаптера
            Если Адаптер.IPAddress <> Неопределено Тогда
                Для Каждого ТекущийIP Из Адаптер.IPAddress Цикл
                    Сообщить("Хост: " + ИмяХоста + " | IP: " + ТекущийIP);
                КонецЦикла;
            КонецЕсли;
        КонецЦикла;
    Исключение
        Сообщить("Не удалось подключиться к WMI компьютера " + ИмяКомпьютера);
    КонецПопытки;
    
КонецПроцедуры

Для локальных проверок внутри сети Windows оптимально использовать Win32_PingStatus с явным указанием таймаута, а для общих проверок стабильности интернет-соединения в современных конфигурациях рекомендуется использовать объект HTTPСоединение.

← На главную