Вопрос или проблема
Мой сервер Windows подключен к сети удаленного офиса через два шлюза по умолчанию.
Шлюзы по умолчанию
172.20.0.1 Первичный
172.20.0.254 Вторичный
// Вторичный подключен с
// 4G SIM-картой VPN
Начальная конфигурация сервера
172.20.0.10 IP-адрес
255.255.255.0 Маска подсети
172.20.0.1 Шлюз по умолчанию
Я хочу запустить пакетный скрипт на сервере, который обнаруживает, когда первичный шлюз 172.20.0.1
выходит из строя, и автоматически переключает сервер на вторичный шлюз 172.20.0.254
и наоборот.
Я хочу обнаруживать сбой, регулярно пингую текущий шлюз.
Пинг 172.20.105.1 с 32 байтами данных:
Ответ от 172.20.0.1: байты=32 время<1мс TTL=255
Ответ от 172.20.0.1: байты=32 время=1мс TTL=255
Ответ от 172.20.0.1: байты=32 время=1мс TTL=255
Когда пинг не проходит, он не возвращает “TTL=”, и скрипт предполагает, что шлюз отключен, и переключается на другой шлюз.
@echo off
setlocal enableextensions enabledelayedexpansion
:loop
ping 172.20.0.1 -n 2
timeout /t 10
set "str1=%~1"
if not "%str1:"TTL="=%" == "%str1%" (
echo "Первичный шлюз НЕДОСТУПЕН"
netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254
)
echo "Данные первичного шлюза ДЕЙСТВИТЕЛЬНЫ"
goto loop
Есть ли более хороший способ сделать это на стороне сервера?
-// ИЗМЕНЕНИЕ //-
Мой более короткий совет:
@echo off && pushd "C:\Windows\System32"
set "_iPs=static 172.20.0.2 255.255.255.0 172.20.0.254"
:loop
=;( ping 172.20.0.1 -n 2 | findstr TTL^= | find /c /v "" );= | find "2" >nul && =;(
timeout 060 /nobreak | echo/Сервер данных отключен, пожалуйста подождите... );= || =;(
echo/Сервер данных отключен, пожалуйста подождите... переключение на резервный сервер.
netsh interface ipv4 set address name="Ethernet" %_iPs%
);= & goto loop & cls
@echo off && setlocal enabledelayedexpansion
set "_gtw#254=netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
set "_msg#001=Первичный шлюз НЕДОСТУПЕН"
set "_msg#002=Данные первичного шлюза ДЕЙСТВИТЕЛЬНЫ"
mode.com con: cols=60 lines=5
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
')do set "_$E=%%~i" & set "_bs=%%~j"
%:^)
title <nul
set "_dns=" <nul
echo/!_$E![1F!_$E![0J
for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^<nul ^| find /v " "')do set "_dns=!_dns!%%~n"
title Шлюз: !_dns!
echo/!_bs!!_$E![1;33m Пожалуйста^^! Подождите несколько секунд...!_$E![0m
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^) || =;(
if "!_dns!" == "172.20.0.1" 2>nul =;(
echo; !_msg#001!
!_gtw#254!
echo; !_msg#002:Первичный=Вторичный!
); else 2>nul =;(
echo; !_msg#001:Первичный=Вторичный!
!_gtw#001!
echo; !_msg#002!
);=
);=
timeout /t 00010 /nobreak >nul
echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E!
goto %:^)
Или…
@echo off && setlocal enabledelayedexpansion
set "_gtw#254=static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_msg#001=Первичный шлюз НЕДОСТУПЕН"
set "_msg#002=Данные первичного шлюза ДЕЙСТВИТЕЛЬНЫ"
set "_gtw#254=netsh interface ipv4 set address name="Ethernet" !_gtw#254!"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
')do set "_$E=%%~i" & set "_bs=%%~j" & mode.com con: cols=60 lines=5
%:^)
title <nul & set "_dns=" <nul & echo/!_$E![1F!_$E![0J
for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^<nul ^| find /v " "')do set "_dns=!_dns!%%~n"
title Шлюз: !_dns! & echo/!_$E![1;33m Пожалуйста^^! Подождите несколько секунд...!_$E![0m
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^) || =;(
if "!_dns!" == "172.20.0.1" 2>nul =;(echo; !_msg#001! & !_gtw#254! & echo; !_msg#002:Первичный=Вторичный!
); else 2>nul =;( echo; !_msg#001:Первичный=Вторичный! & !_gtw#001! & echo; !_msg#002! );=
);= & timeout /t 00010 /nobreak >nul & echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E! & goto %:^)
Есть ли более хороший способ сделать это на стороне сервера?
- Да, если я учту приведенные ниже моменты:
1. Ваш код в вопросе не определяет, является ли текущий шлюз первичным, и было ли уже выполнено переключение на вторичный шлюз.
2. Переключение шлюза с вторичного на первичный никогда не произойдет в случае сбоя вторичного шлюза.
3. Ваши echo
и netsh
команды будут выполняться, только если ваш первичный используется и выходит из строя соответствующим образом, но только в этом условии первый используется и в первый раз в цикле, после этого второй шлюз будет всегда повторно настроен для использования, даже когда отключен.
4. %~1
в set "str1=%~1"
не имеет смысла в вашем вопросе из-за отсутствия ссылки на аргумент(ы), используемые и/или цели сравнения, где аргумент %~1
определяет переменную str1
, и ее подстрока ("%str1:"TTL="=%"
) сравнивается:
set "str1=%~1"
if not "%str1:"TTL="=%" == "%str1%"
P.S.С этого момента обращайтесь к коду в вашем ответе...
5. Пункты, указанные в вышеупомянутых пунктах 1., 2. и 3., также повторяются в ваших действиях/эффектах в вашем текущем ответе.
6. Нет необходимости создавать файл при перенаправлении вашей команды ping, и замена, где вывод опускается с >nul
, а перенаправление к оператору &&
(возврат 0), ||
(возврат не 0) может дать тот же результат без дополнительных ìfs
, помня, что при закрытии batch скрипт, созданный файл останется там без использования.
ping 172.20.0.1 -n 2 > pingtest.txt
if %errorlevel%==0 goto waiting
ping 172.20.0.1 -n 2 >nul && goto waiting
P.S.С этого момента обращайтесь к версии #1 этого ответа
Будет произведено будущее изменение с добавлением описаний действий/команд, но это будет сделано в мое свободное время.
a) Определите ваши переменные и также разрешите использование подстрок в этом определении или ваших командах, что позволяет сделать соответствующее изменение для Шлюз .1 и Шлюз .254 с:
set "_gtw#254=netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
set "_msg#001=Первичный шлюз НЕДОСТУПЕН"
set "_msg#002=Первичный Данные ДЕЙСТВИТЕЛЬНЫ"
...
if "!_dns!" == "172.20.0.1" 2>nul =;(
echo; !_msg#001!
!_gtw#254!
echo; !_msg#002:Первичный=Вторичный!
);= else =;(
echo; !_msg#001:Первичный=Вторичный!
!_gtw#001!
echo; !_msg#002!
);=
b) Получите вывод команды netsh interface ipv4 show config
в первом цикле for /f
, и используйте соответствующий токен/разделитель, чтобы получить IP DNS/Шлюза, используемого в данный момент, а во втором цикле for /f
отфильтруйте/удалите любые пробелы с find /aVoid " " ...
:
for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^>nul ^| find /v " "')do set "_dns=!_dns!%%~n"
c) Используемая команда ping
займет около 10 секунд, поэтому можно использовать заголовок с отображением уже полученного DNS/Шлюза и дополнительно какое-то сообщение, отображаемое во время этого времени, чтобы дать пользователю знак, что идет активность:
title Шлюз: !_dns!
echo/!_bs!!_$E![1;33m Пожалуйста^^! Подождите несколько секунд...!_$E![0m
d) В случае кода, который будет работать в :loop
, откуда я предполагаю, что его использование не случайно и что его выполнение будет продолжаться некоторое время, нет причин не иметь некоторой дополнительной доработки, такой как цвет текста, используя ANSI, и вместо того, чтобы очищать весь экран с cls
, делать это только на соответствующих строках, помимо того, чтобы поддерживать экран в размерах “отрегулированных” mode
для текста, который будет отображаться:
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
')do set "_$E=%%~i" & set "_bs=%%~j" & mode.com con: cols=60 lines=5
:: $E установить _$E [%%~i] в ESC Символ
:: $H установить _bs [%%~j] в Символ BackSpace
:: Отображаемый размер/буфер - количество колонок и количество строк:
:: MODE CON[:] [COLS=c] [LINES=n]
:: mode.com con: cols=60 lines=5
title >nul & ... echo/!_$E![1F!_$E![0J
...
title Шлюз: ... echo/!_$E![1;33m Пожалуйста^^! Подождите несколько секунд...!_$E![0m
e) Установите ping
число (-n 6
) и подсчитайте (find /Count
) количества выходов “TTL
“, используя перенаправитель |
и пропуская вывод на экране (>nul
), также в этом процессе обработки команд сделайте выгодное использование операторов &&
и ||
, чтобы определить соответствующие действия в зависимости от возврата 0
и возврата не 0
:
ping !_dns! -n 6 | find /c "TTL" | find "6" <nul && .. || ...
ваша команда ping && (
echo/ Вернулся 0
) || (
echo/ Вернулся не 0
)
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^)
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul || if condition() else()
f) Использование оператора в условии возврат 0
, чтобы вернуться к перезапуску действий по получению DNS/Шлюза
, и снова ping
с timeout
соответствующего интервала, в случае если количество “TTL” не совпадает, if
принимает условие, чтобы возврат не 0
, и определяет текущий DNS/Шлюз
, предполагая компоновку текста и соответствующей команды, используя varible:substrings=?
, относящиеся к условию, компонуя соответствующий текст и команду:
if "!_dns!" == "172.20.0.1" 2>nul =;(
echo; !_msg#001!
!_gtw#254!
echo; !_msg#002:Первичный=Вторичный!
);= else =;(
echo; !_msg#001:Первичный=Вторичный!
!_gtw#001!
echo; !_msg#002!
);=
g) После действий, обработанных в вышеупомянутых пунктах, timeout
остается для выполнения командного цикла для новых диагностик и соответствующих действий, основанных на возвращаемых командах, затем ожидание, за которым следует очистка (echo/ ESC[ANSI коды
) использованных строк и перенаправление на goto
метку %:^)
, которая запускает новый цикл, идеально соответствующий этим действиям:
timeout /t 00010 /nobreak >nul
echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E!
goto %:^)
Читать далее:
Спасибо всем. Я нашел более короткий способ для этого.
Вот как..
@echo off
cls
:starting
ping 172.20.0.1 -n 2 > pingtest.txt
c:\windows\system32\findstr.exe "TTL=" pingtest.txt
if %errorlevel%==0 goto waiting
echo "ДАННЫЕ ОТОКЛЮЧЕНЫ, переключаюсь на РЕЗЕРВНУЮ СЕТЬ"
netsh interface ipv4 set address name="Ethernet" static 172.20.0.2 255.255.255.0 172.20.0.254
timeout /t 60
:waiting
echo "ДАННЫЕ РАБОТАЮТ, жду задержку"
timeout /t 60
goto starting
Ответ или решение
Для автоматизации переключения маршрутизаторов на сервере Windows с использованием пакетного скрипта, который будет реагировать на недоступность основного шлюза (172.20.0.1), необходимо создать скрипт, который будет периодически проверять соединение с основным шлюзом с помощью команды ping
. Если соединение не удалось, скрипт должен переключиться на вторичный шлюз (172.20.0.254). Давайте создадим наиболее оптимизированный и понятный скрипт для решения данной задачи.
Вот пример пакетного скрипта для реализации описанной логики:
@echo off
setlocal enabledelayedexpansion
:: Определяем IP-адреса и настройки
set "PRIMARY_GATEWAY=172.20.0.1"
set "SECONDARY_GATEWAY=172.20.0.254"
set "INTERFACE_NAME=Ethernet"
set "IP_ADDRESS=172.20.0.10"
set "SUBNET_MASK=255.255.255.0"
:loop
cls
echo Проверка основного шлюза: %PRIMARY_GATEWAY%
ping -n 2 %PRIMARY_GATEWAY% | find "TTL=" >nul
if !errorlevel! equ 0 (
echo Основной шлюз доступен.
) else (
echo Основной шлюз недоступен, переключение на вторичный шлюз.
netsh interface ipv4 set address name="%INTERFACE_NAME%" static %IP_ADDRESS% %SUBNET_MASK% %SECONDARY_GATEWAY%
timeout /t 10
goto loop
)
echo Ожидание 60 секунд перед следующей проверкой...
timeout /t 60
goto loop
Описание работы скрипта:
-
Инициализация переменных: В начале скрипта определяются переменные для основных IP-адресов, маски подсети и имени интерфейса.
-
Главный цикл проверки: Используется метка
:loop
для организации бесконечного цикла. В этом цикле происходит очистка экрана, выполнение командыping
для проверки доступности основного шлюза. -
Проверка результатов команды
ping
:- Если
ping
успешен (возвращаетTTL=
), выводится сообщение о доступности основного шлюза. - Если
ping
не удался, выполняется переключение на вторичный шлюз с помощью командыnetsh
.
- Если
-
Таймер: После проверки, если основной шлюз доступен, запускается таймер на 60 секунд, после чего снова начинается проверка.
Рекомендации по дополнениям:
- Если требуется не только переключение на вторичный шлюз, но и обратно на основной, можно сохранить информацию о текущем активном шлюзе и при последующих проверках, если основной оказывается доступным, возвращать его обратно.
- Для повышения надежности, можно рассмотреть возможность использования более сложной проверки (например, добавление дополнительных
ping
для ожидания до полной доступности).
С помощью данного скрипта вы сможете эффективно управлять маршрутизацией с учетом доступности сетевых шлюзов, что значительно повысит стабильность подключения вашего сервера к сети.