При разработке интеграций, обменов данными или систем мониторинга сетевого оборудования в 1С часто возникает задача проверить доступность удаленного сервера, кассы, сетевого принтера или интернет-канала. На практике разработчики сталкиваются с тем, что стандартный запуск утилиты ping через командную строку возвращает ложный признак успешности соединения.
Разберем причины такого поведения, выясним, почему системный вызов может выдавать неверный результат, и детально рассмотрим надежные способы проверки связи из 1С без использования внешних компонент и временных текстовых файлов.
Проанализируем типичную ошибку при попытке выполнить проверку через WScript.Shell:
Процедура КнопкаВыполнитьНажатие(Кнопка)
Адр = "80.252.128.110";
wss = Новый COMОбъект("WScript.Shell");
Результат = Не wss.Run("ping -w 1500 -n 1 " + Адр, 0, Истина);
КонецПроцедуры
Выясним причину, почему переменная Результат может принимать значение Истина, даже если интернет-канал на роутере фактически отключен (например, вынута SIM-карта или заблокирован счет провайдера):
0 (успех) не только тогда, когда получен ответ от целевого узла, но и в случае, когда локальный шлюз (роутер) возвращает ICMP-сообщение «Destination host unreachable» (узел назначения недоступен). Физическая связь между компьютером и роутером сохраняется, роутер отвечает сетевому стеку компьютера об ошибке маршрутизации, и ОС считает команду успешно отработавшей.Наиболее точным и быстрым способом в среде 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 Тогда
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Рассмотрим подробнее важные параметры данного запроса:
1000 мс).0 свидетельствует об успешном ответе целевого узла (Success). Любые другие коды (например, 11003 — Host Unreachable, 11010 — Request Timed Out) говорят об отсутствии связи.Если требуется изолировать логику выполнения запроса в рамках скриптового движка 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С.
Если основная цель — проверить наличие фактического подключения к сети Интернет или доступность конкретного веб-сервера (а не просто прохождение ICMP-пакетов внутри локальной сети), наиболее надежным и платформонезависимым решением является объект HTTPСоединение.
Разберем реализацию проверки без использования внешних утилит и COM-объектов:
Функция ПроверитьИнтернетСоединение(Знач АдресСервера = "ya.ru", Знач Таймаут = 3) Экспорт
Попытка
// Создаем защищенное или обычное соединение с коротким таймаутом
Соединение = Новый HTTPСоединение(АдресСервера, 443, , , , Таймаут, Новый ЗащищенноеСоединениеOpenSSL());
Запрос = Новый HTTPЗапрос("/");
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния >= 200 И Ответ.КодСостояния < 400 Тогда
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
Исключение
// Ошибка соединения, таймаут или отсутствие сети
Возврат Ложь;
КонецПопытки;
КонецФункции
Преимущества такого подхода:
Если в рамках задачи системного администрирования требуется не только проверить пинг, но и получить 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Соединение.