N
nikostap
Гость
Я искал простое решение, которое позволяло бы одной кнопкой удалённо включать и выключать компьютер.
С включением всё давно решено: отправляешь стандартный Wake‑on‑LAN magic packet — и компьютер запускается. Но с выключением оказалось сложнее. Готового и удобного варианта, который работал бы по такому же принципу, я не нашёл. Большинство решений требовали отдельного приложения, удалённого рабочего стола, SSH, умной розетки или установки целого комплекса для управления компьютером.
Хотелось, чтобы всё было максимально просто: одна и та же кнопка отправляет один и тот же Wake‑on‑LAN пакет. Если компьютер выключен — сетевая карта принимает пакет и включает его. Если Windows уже работает — пакет перехватывает фоновая служба и выключает компьютер.
В итоге я решил по‑быстрому накидать нужное решение с помощью нейросети. Получилась небольшая Windows‑служба, которая:
- автоматически запускается вместе с Windows;
- работает в фоне без открытых окон;
- слушает выбранный UDP‑порт;
- проверяет структуру Wake‑on‑LAN magic packet;
- сверяет MAC‑адрес назначения;
- выключает компьютер после получения правильного пакета.
Получается простой переключатель: один magic packet — компьютер меняет своё состояние. Если он выключен, то включается средствами Wake‑on‑LAN. Если включён — служба принимает тот же пакет и запускает штатное выключение Windows.
Служба уже работает на моём компьютере, поэтому решил привести проект в порядок и поделиться им со всеми. Исходники, инструкция по установке и готовая сборка опубликованы в репозитории WakeUpOnLan Shutdown.
Что представляет собой magic packet
Стандартный Wake‑on‑LAN пакет состоит из:
- Шести байтов
FF. - Шестнадцати повторений MAC‑адреса целевого устройства.
Минимальный размер такой последовательности — 102 байта:
Код:
FF FF FF FF FF FF
AA BB CC DD EE FF
AA BB CC DD EE FF
...
MAC повторяется 16 раз
Служба не реагирует на любой пакет, прилетевший на UDP‑порт. Она ищет внутри полученных данных правильную последовательность и проверяет все 16 повторений MAC.
Упрощённо проверка выглядит так:
Код:
for (var offset = 0; offset <= packet.Length - 102; offset++)
{
if (!packet.Slice(offset, 6)
.SequenceEqual(new byte[] { 255, 255, 255, 255, 255, 255 }))
{
continue;
}
var mac = packet.Slice(offset + 6, 6);
for (var repetition = 1; repetition < 16; repetition++)
{
if (!packet
.Slice(offset + 6 + repetition * 6, 6)
.SequenceEqual(mac))
{
return false;
}
}
return true;
}
Дополнительно MAC из пакета сравнивается с MAC сетевого адаптера компьютера. Если MAC не задан вручную, служба находит интерфейс по указанному локальному IP и определяет его физический адрес автоматически.
Таким образом, WoL‑пакет для другого устройства не приведёт к выключению ПК.
Прослушивание UDP
Адрес и порт задаются в
appsettings.json:
Код:
{
"BindAddress": "192.168.1.50",
"Port": 9,
"TargetMac": "",
"ShutdownDelaySeconds": 10,
"ForceCloseApplications": false,
"FirewallRemoteAddress": "Any"
}
Служба создаёт UDP‑сокет и привязывается к конкретному локальному адресу:
Код:
using var udp = new UdpClient(AddressFamily.InterNetwork);
udp.Client.Bind(
new IPEndPoint(bindAddress, settings.Port)
);
var received = await udp.ReceiveAsync(cancellationToken);
Привязка к конкретному IP помогает избежать неоднозначности на компьютерах с несколькими сетевыми адаптерами.
Если при старте Windows сеть ещё не поднялась или адрес временно отсутствует, служба не завершается окончательно, а повторяет попытку через 15 секунд.
Выключение Windows
После получения корректного пакета запускается стандартная системная команда:
Код:
shutdown.exe /s /t 10
По умолчанию я оставил задержку 10 секунд. За это время выключение можно отменить:
Код:
shutdown /a
Принудительное закрытие приложений отключено. Его можно включить параметром:
Код:
"ForceCloseApplications": true
Но в этом режиме возможна потеря несохранённых данных.
Почему именно Windows‑служба
Обычную программу пришлось бы добавлять в автозагрузку и запускать после входа пользователя. Windows‑служба работает независимо от интерактивного сеанса и стартует вместе с системой.
Служба устанавливается с типом запуска
Automatic и работает от имени LocalSystem. Для взаимодействия с диспетчером служб используются функции Windows API:
Код:
StartServiceCtrlDispatcher(...)
RegisterServiceCtrlHandlerEx(...)
SetServiceStatus(...)
Такой вариант позволил не добавлять отдельные NuGet‑зависимости для Windows Services.
Приложение также поддерживает консольный режим:
Код:
.\WakeOnLanShutdown.exe --console
Он удобен для диагностики до установки службы.
Установка на другой компьютер
В разделе Releases находится готовая автономная сборка для Windows x64.
После распаковки нужно открыть
appsettings.json и указать постоянный локальный IP компьютера:
Код:
"BindAddress": "192.168.1.50"
Лучше не назначать статический адрес непосредственно в Windows, а создать DHCP reservation на роутере. Тогда компьютер продолжит получать сетевые настройки автоматически, но всегда будет получать один и тот же IP.
После настройки нужно открыть PowerShell от имени администратора и выполнить:
Код:
Set-ExecutionPolicy -Scope Process Bypass
.\install.ps1
Установщик:
- копирует программу в
C:\Program Files\WakeOnLanShutdown; - создаёт службу
WakeOnLanShutdown; - включает автоматический запуск;
- настраивает перезапуск после сбоя;
- создаёт входящее правило брандмауэра Windows;
- запускает службу.
Проверить состояние можно так:
Код:
Get-Service WakeOnLanShutdown
Get-NetUDPEndpoint -LocalPort 9
Журнал находится здесь:
Код:
C:\ProgramData\WakeOnLanShutdown\service.log
Доступ через интернет
Если отправлять пакет не только из локальной сети, на роутере потребуется перенаправление UDP‑порта:
Код:
Внешний UDP-порт → локальный IP компьютера → порт 9
Например:
Код:
UDP 40009 → 192.168.1.50:9
В приложении‑отправителе тогда указывается публичный IP или DDNS‑имя роутера, внешний порт
40009 и MAC компьютера.Внешний порт необязательно делать девятым. Нестандартный номер немного уменьшит количество случайного сетевого шума, хотя полноценной защитой это не является.
Если провайдер использует CG‑NAT, обычный port forwarding работать не будет. В таком случае нужен публичный IP либо VPN с доступом в домашнюю сеть.
Важный момент о безопасности
Wake‑on‑LAN не содержит нормальной аутентификации. MAC‑адрес — это идентификатор устройства, а не секретный пароль.
Если открыть UDP‑порт всему интернету, любой человек, узнавший MAC компьютера, теоретически сможет отправить подходящий пакет и инициировать выключение.
Поэтому для постоянного использования лучше:
- подключаться к домашней сети через WireGuard или Tailscale;
- не публиковать UDP‑порт напрямую;
- либо ограничить
FirewallRemoteAddressсвоим постоянным внешним IP:
Код:
"FirewallRemoteAddress": "203.0.113.10"
Можно также указать CIDR‑подсеть.
Сборка из исходников
Для самостоятельной сборки нужен.NET 8 SDK:
Код:
git clone https://github.com/nikostap/WakeUpOnLan\_Shutdown.git
cd WakeUpOnLan_Shutdown
Set-ExecutionPolicy -Scope Process Bypass
.\build.ps1
Скрипт создаёт self‑contained сборку для
win-x64. На целевом компьютере устанавливать.NET Runtime не требуется.Перед установкой можно запустить встроенный тест проверки пакетов:
Код:
.\publish\WakeOnLanShutdown.exe --self-test
Ожидаемый результат:
Код:
Self-test: OK
Удаление
Для удаления службы и правила брандмауэра достаточно выполнить от имени администратора:
Код:
.\uninstall.ps1
Установленные файлы намеренно не удаляются автоматически, чтобы случайно не потерять конфигурацию.
Что получилось
В результате получилась небольшая автономная Windows‑служба без внешней инфраструктуры и сторонних серверов. Она запускается вместе с системой, почти не требует обслуживания и использует обычный Wake‑on‑LAN пакет в качестве сигнала для выключения.
Исходники, инструкция и готовая сборка опубликованы на GitHub:
github.com/nikostap/WakeUpOnLan_Shutdown
Источник: habr.com


