---
url: /article/u0ns75tk/index.md
---
## 前言

Wake-on-LAN(WOL, 网络唤醒)是一种以太网或令牌环计算机标准，允许通过网络消息开启或唤醒睡眠模式的计算机。该消息通常由连接到同一局域网 (LAN) 的设备上运行的程序发送到目标计算机。也可以通过使用子网定向广播或 WoL 网关服务从另一个网络发起消息。它基于 AMD 的 Magic Packet 技术 ，该技术由 AMD 和惠普共同开发，并于 1995 年被提议作为标准。

简而言之，就是能在局域网下通过发送魔术包的方式唤醒计算机。这有什么好处呢？

> 试想一个场景，你的家里有一台配置比较高的电脑或服务器，安装一些开发环境，启动了一些服务：Nginx、Redis、Mysql、Kafka 等等。由于配置高又运行这么些服务，功耗也同样高，所以我们必然不会全天候运行，所以想过弄一个低功耗的小主机/小型服务器，7x24 小时不间断运行。
> 我考虑过迷你主机、Nas主机，但它们被设计的使用场景都不符合我的需求。看过不少品牌的迷你主机，它的性能通常比Nas高，但又不如我们的标准主机，而且它的扩展性也不如标准主机，如果运行我们开发所需的服务，它的功耗一样不会低，那么小的机身还要给它散热，有点太为难它的，那要它做甚？\
> 至于Nas，它的设计目标在于数据存储和共享，通常是 7x24 小时不间断运行，所以要在功耗和性能上做平衡。\
> 说来说去，又回到了问题的起点。那就换一种解决思路，能不能在需要的时候开启，不用的时候关闭呢？当然可以，这就需要用到 WOL 技术了。

## 1. 设置唤醒

要想开启 Windows 的 WOL 功能有两个部分需要设置：BIOS设置、网卡设置。

### 1.1 BIOS设置

不同主板进入 BIOS 的方式不同，都可以谷歌得到，这里以我的微星主板为例。\
电脑开启时按`DEL`键进入，在`SETTING` -> `高级` -> `唤醒事件设置`，允许`网络唤醒`即可。同时还有一项`PCIE设备唤醒`，字面意思很容易理解，网卡就是一种`PCIE设备`，所以允许`网络唤醒`其实也就是允许`PCIE设备唤醒`，只不过微星把这两个概念拆开了。可能在有的主板上就只有一项`PCIE设备唤醒`，打开它也是一样的。但`PCIE设备`并不仅仅只有网卡，其他任何一个开发板只要是有 PCIE 接口可以插在主板上，那么它也可以成为唤醒设备，这其实就是留了一个`开放接口`的意思，你可以做各种 DIY 实现。这样，我们就可以实现电脑在`睡眠/休眠`中被唤醒了。

另外，在`电源管理设置`中有一项`ERP/ErP Ready`，它默认是打开的，如果想要电脑在**关机下也能被唤醒**，那就需要关闭它。ErP的意思是与能源有关的产品，它与欧盟对各种电子产品（包括个人电脑）通过的环境法规有关。启用 BIOS 里的 ErP 模式或使用 ErP Ready 设置，将使你的个人电脑在关闭时，可以关闭流向所有组件的电源，将总的电力消耗减少到1瓦或更少。\
说人话就是，禁用 ErP 在关机下几乎不耗电池，此时也不允许你用鼠标或键盘唤醒电脑，不能对传入的局域网信号作出反应，也就是说远程网络唤醒功能也因此失效了，那我们自然要禁用它。可能你会担心禁用后会好很多电吗？实际上并不会，禁用 ErP 后也就比启用它在关机下的功能多 1~2W，但这根本无所谓。按照民电 0.68元/度，2W 的设备 7x24 小时不间断运行，一年下来需要 11.91元的电费，相对于你在这一年里的开销来说，这不过于九牛一毛。

### 1.2 网卡设置

开机进入系统，按下`win+R`输入`ncpa.cpl`会打开`网络连接`，选择你当前使用的那个网卡(插的是网线就选`以太网`，连的 wifi 就选`WLAN`)，找到`属性` -> `配置` -> `电源管理`，勾选`允许此设备唤醒计算机`\[+wol]和`只允许幻数据包唤醒计算机`(可选，但建议开启)\[+wol\_only]，并取消勾选`允许关闭计算机关闭此设备以节约电源`\[+wol\_power\_off]。
\[+wol]:**作用**：启用后，网卡可以在计算机处于睡眠(S3)或休眠(S4)状态时，通过特定信号唤醒计算机。
\[+wol]:**如何工作**：这意味着，网卡不仅会响应“魔术数据包”(WOL数据包)，还可能响应其他网络活动(如收到数据包、网络流量等)来唤醒计算机。
\[+wol\_only]:**作用**：启用后，网卡只会响应特定的`魔术数据包`来唤醒计算机，而不会响应其他任何网络活动或流量。魔术数据包的格式是：数据包头包含16个字节，的全0和6个字节的全1，后面跟着目标计算机的`MAC地址`，并重复16次。
\[+wol\_only]:**如何工作**：魔术数据包是一种特定格式的数据包，其中包含目标计算机的网卡`MAC地址`。该选项确保只有发送这种特定格式的数据包时，计算机才会被唤醒，从而提高唤醒的精确性和安全性。
\[+wol\_power\_off]:当启用时，操作系统会让网络适配器在计算机进入休眠或关机时进入`省电模式`，此时网卡会被完全关闭或进入低功耗状态，网卡**无法接收任何网络请求或魔术数据包**，无法唤醒计算机。

## 2. 电源状态

在 ACPI(高级配置与电源接口)规范中，定义了从 S0 到 S5 的一系列电源状态，用于描述操作系统如何控制计算机的电源管理。

|状态|名称|描述|
|:--:|:--:|:--:|
|S0|工作状态(Working)|系统完全运行，所有硬件设备正常供电|
|S1|待机状态(Standby)|CPU 停止执行指令，但保持供电，内存保留内容，唤醒非常快|
|S2|深度待机状态(Deeper Sleep)|类似 S1，但 CPU 和缓存完全断电；更省电，唤醒稍慢。很少使用|
|S3|睡眠状态(Sleep/Suspend to RAM)|**内存保持供电**，CPU 和外设断电；唤醒速度较快，常见的“睡眠”模式|
|S4|休眠状态(Hibernate/Suspend to Disk)|**将内存内容保存到硬盘**，然后全部断电；唤醒时从磁盘恢复，速度较慢，但更省电|
|S5|关机状态(Soft Off)|系统完全关闭，几乎无功耗，但仍可通过特定事件(如唤醒信号)启动|

可能之前我们会把睡眠(S3)和休眠(S4)弄混淆，事实上它们的定义标准是不同的。由于 RAM 的读写速度非常高，当我们从睡眠模式下唤醒到进入系统页面，通常只需要 2~3 秒；但硬盘的读写速度远不如 RAM ，即便是一个 SSD 硬盘，从休眠模式下唤醒到进入系统页面，可能也需要 7~8 秒。\
在 Windows11 系统中，我们发现只能看到`睡眠`，其实默认下`休眠`是被隐藏了，因为 Windows11 系统的`关机`和`休眠`就比较类似了，一样是把工作内容保存在硬盘，使得开机后可以迅速恢复。

按下`win+R`输入`control`打开`控制面板`，选择`电源选项`。在左侧的`选择电源按钮的功能`中可以看到`休眠`是没有被勾选的，我们可以勾选上\[+power]，这样在按下`Win`键并点击`关机`按钮时就可以看到`休眠`的选项了。\
同时，我们注意的电源选项中还有一项`启用快速启动(推荐)`，它是默认被勾选的，正是由于启用了它，才得以让`关机`的效果和`休眠`类似，Windows 刻意隐藏了`休眠`开关，想用`快速启动`下的关机来达到`休眠`效果，也避免了`休眠`和`睡眠`的含义比较接近，导致用户感觉到歧义。
\[+power]: 默认在`关机设置`栏无法修改，此时点击上方的`更改当前不可用设置`即可。

此时，电脑就设置好了 WOl 唤醒了。可以通过`Fing`应用(支持Android和IOS)其中的`LAN唤醒`来验证，IOS 系统亦可下载`Awake`应用(免费无广，且可集成在`快捷指令`中)验证。如果有 OpenWrt 的软路由系统，可以安装`luci-i18n-wol-zh-cn`，将`网络唤醒`集成在 OpenWrt 中，便于操作。

至此，就已经设置好了主机网络唤醒。

## 3.设置休眠

上面说的都是把主机从`睡眠/休眠/关机`状态下唤醒，那么我们还想要在主机醒着的状态下进入到`睡眠/休眠/关机`状态如何做呢？这里当然不是要说在电脑上通过点击来操作，这样没有意思，我们需要通过**指令**的方式让主机进入到`睡眠/休眠/关机`状态。

通过命令行(cmd)窗口执行`shutdown --help`可以看到指令支持的操作如下：

```cmd :collapsed-lines=5 :no-line-numbers
用法: shutdown [/i | /l | /s | /sg | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/soft] [/fw] [/f]
    [/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]

    没有参数   显示帮助。这与键入 /? 是一样的。
    /?         显示帮助。这与不键入任何选项是一样的。
    /i         显示图形用户界面(GUI)。
               这必须是第一个选项。
    /l         注销。这不能与 /m 或 /d 选项一起使用。
    /s         关闭计算机。
    /sg        关闭计算机。在下一次启动时，如果启用了
               自动重启登录，则将自动登录并锁定上次交互用户。
               登录后，重启任何已注册的应用程序。
    /r         完全关闭并重启计算机。
    /g         完全关闭并重启计算机。重新启动系统后，
               如果启用了自动重启登录，则将自动登录并
               锁定上次交互用户。
               登录后，重启任何已注册的应用程序。
    /a         中止系统关闭。
               这只能在超时期间使用。
               与 /fw 结合使用，以清除任何未完成的至固件的引导。
    /p         关闭本地计算机，没有超时或警告。
               可以与 /d 和 /f 选项一起使用。
    /h         休眠本地计算机。
               可以与 /f 选项一起使用。
    /hybrid    执行计算机关闭并进行准备以快速启动。
               必须与 /s 选项一起使用。
    /fw        与关闭选项结合使用，使下次启动转到
               固件用户界面。
    /e         记录计算机意外关闭的原因。
    /o         转到高级启动选项菜单并重新启动计算机。
               必须与 /r 选项一起使用。
    /m \\computer 指定目标计算机。
    /t xxx     将关闭前的超时时间设置为 xxx 秒。
               有效范围是 0-315360000 (10 年)，默认值为 30。
               如果超时期限大于 0，则 /f 参数为
               /f 参数。
    /c "comment" 注释重启或关闭的原因。
               最多允许 512 个字符。
    /f         强制关闭正在运行的应用程序而不事先警告用户。
               当大于 0 的值为
 时，隐含 /f 参数               则默示为 /f 参数。
    /d [p|u:]xx:yy  提供重新启动或关闭的原因。
               p 指示重启或关闭是计划内的。
               u 指示原因是用户定义的。
               如果未指定 p 和 u，则
重新启动或关闭               是计划外的。
               xx 是主要原因编号(小于 256 的正整数)。
               yy 是次要原因编号(小于 65536 的正整数)。

此计算机上的原因:
(E = 预期 U = 意外 P = 计划内，C = 自定义)
```

这里关注几个我们需要的：

|指令|效果|
|:--:|:--:|
|shutown /s|关机|
|shutown /h|休眠|
|shutown /r|重启|

但是，我们没有看到`睡眠`的指令。经过一番搜索，找到两条`指令`可以实现`睡眠或休眠`的效果：`rundll32.exe powrprof.dll,SetSuspendState 0,1,0`或`rundll32.exe powrprof.dll,SetSuspendState Sleep`。这两种指令经过验证效果是一样的。\
为什么说是实现`睡眠或休眠`的效果呢？即`睡眠`和`休眠`只能二选一，那什么时候是睡眠，什么时候是休眠呢？

默认情况下，`休眠`功能是启用的，那么上面的`指令`效果就是休眠，则它等价于`shutown /h`。可以通过`powercfg -h off`(powershell 管理员权限)来关闭`休眠`功能，此时`shutdown /h`指令会失效，同时在`电源选项`中亦不存在`休眠`和`启用快速启动(推荐)`的设置，而`指令`的效果也就变成`睡眠`了。所以，需要斟酌一下，到底要不要关闭`休眠`功能。如果关闭`休眠`后想再次打开，可执行`powercfg -h on`。\
如何分辨是从睡眠中醒来，还是从休眠中醒来？查看主机唤醒时，显示器有没有显示主板BIOS的图案，如果有就说明是从休眠中醒来，否则不是。

## 4. 进阶操作

如何便捷地通过 iPhone 在局域网下唤醒/休眠主机？这里我总结了一套实践经验。\
因为 IOS 的快捷指令中支持 SSH 连接并发送指令，那么完全可以通过 SSH 连接到 OpenWrt/Windows 来实现唤醒/休眠主机，但是考虑到操作统一性和便捷性，我实际的做法是：

```mermaid
flowchart LR
    IOS --> |HTTP| OpenWrt
    OpenWrt --> |SSH| Windows
```

### 4.1 Windows 部分

然而在实操踩坑中发现，对于`shutdown /s`(关机)和`shutdown /r`(重启)的指令响应逻辑没问题，但是`睡眠`或`休眠`就有问题了，直接执行相关命令会导致，主机刚进入`睡眠`或`休眠`状态又立即被唤醒了。\
因此我在 Windows 用户目录下放了两个`bat`脚本，定义了临时触发器来执行操作，供 OpenWrt 通过 SSH 调用，具体如下。

::: code-tabs
@tab trigger\_sleep.bat

```bat:no-line-numbers
@echo off
setlocal

:: 获取当前时间 + 1 分钟
for /f "tokens=1,2 delims=:" %%a in ("%time%") do (
    set /a hh=1%%a %% 100
    set /a mm=1%%b + 1
)
if %mm% GEQ 60 (
    set /a mm=0
    set /a hh+=1
)
if %hh% GEQ 24 set /a hh=0

:: 格式化为 HH:MM（确保补零）
set hh=0%hh%
set mm=0%mm%
set hh=%hh:~-2%
set mm=%mm:~-2%

:: 创建一次性计划任务，执行“睡眠”
schtasks /create /tn "TriggerSleep" /tr "rundll32.exe powrprof.dll,SetSuspendState 0,1,0" /sc once /st %hh%:%mm% /f >nul
schtasks /run /tn "TriggerSleep" >nul

echo Will sleep at %hh%:%mm%
endlocal
```

@tab trigger\_hibernate.bat

```bat:no-line-numbers
@echo off
setlocal

:: 获取当前时间 + 1 分钟
for /f "tokens=1,2 delims=:" %%a in ("%time%") do (
    set /a hh=1%%a %% 100
    set /a mm=1%%b + 1
)
if %mm% GEQ 60 (
    set /a mm=0
    set /a hh+=1
)
if %hh% GEQ 24 set /a hh=0

:: 格式化为 HH:MM（确保补零）
set hh=0%hh%
set mm=0%mm%
set hh=%hh:~-2%
set mm=%mm:~-2%

:: 创建一次性计划任务
schtasks /create /tn "TriggerHibernate" /tr "shutdown /h" /sc once /st %hh%:%mm% /f >nul
schtasks /run /tn "TriggerHibernate" >nul

echo Will hibernate at %hh%:%mm%
endlocal
```

:::

这两个脚本，`trigger_sleep.bat`是用来触发`睡眠`指令，`trigger_hibernate.bat`是用来触发`休眠`指令。

如果想通过 SSH 来管理 Windows 系统，就需要安装`OpenSSH`服务，Windows11 默认已经安装了 SSH 的客户端，此时我们安装服务端。\
有两种方式安装：

方式一：\
进入`设置`->`系统`->`可选功能`->`添加可选功能`，搜索`OpenSSH 服务器`安装\[+openssh]。

方式二：

```powershell:no-line-numbers
# 安装
Add-WindowsFeature -Name OpenSSH-Client, OpenSSH-Server
# 安装完成后就自动运行了
# 查看
Get-Service -Name sshd
# 连接测试
ssh localhost
```

设置为开机自启：按`WIN`键搜索`计算机管理`，然后打开`服务`找到`OpenSSH SSH Server`，修改属性将`启动类型`调整为`自动(延迟启动)`。
\[+openssh]: windwos系统版本不同可能入口不太一样，有的是在`设置`->`应用`->`可选功能`->`添加可选功能`

可以借助**Git bash**生成密钥，执行`ssh-keygen -t rsa -f ~/.ssh/id_rsa`(生成RSA密钥)或`ssh-keygen -t ed25519 -f ~/.ssh/id_rsa`(生成ed25519密钥)，前者广泛兼容，后者安全性更高，随便选择一种即可。\
然后把生成的密钥对中的公钥内容复制到 Windwos 用户目录下的`.ssh\authorized_keys`文件中，如果文件不存在可自行创建，注意文件没有后缀。示例：

```text title="authorized_keys" :no-line-numbers
  ssh-rsa AAAAB4NzaC1yc2EAAAADAQABAAABAQCC8P8z96xo2EcfejdrvEt/6Tc2qhX7FhLevcqjhNvQYPYmQaMwZElsi0QAABAQCC9P8z96xo1EcfejdrvdrvEt/9Tc2q root@ImmortalWrt
```

接着就是 Windows 的特有操作，更改`authorized_keys`文件权限，否则无法通过密钥登录。以下命令**二选一**即可：

```bash :no-line-numbers
  # 远程通过 ACL 更改权限
  ssh --% mayee@192.168.0.88 icacls.exe "C:\Users\mayee\.ssh\authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" /grant "mayee:F"
  # 服务端修改权限
  icacls.exe "C:\Users\mayee\.ssh\authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" /grant "maye:F"
```

注意：这个操作是授权，表示`Administrators`、`SYSTEM`和`mayee`将有完全控制权限，一定要把自己的用户名加上，否则之后无法修改此文件。如果忘了加可以用此命令补`icacls "C:\Users\mayee\.ssh\authorized_keys" /grant "mayee:F"`。

在 Windows OpenSSH 中，默认的授权密钥存放位置为`ProgramData\ssh\administrators_authorized_keys`，此位置对应为管理用户权限。因此需要修改默认授权文件位置。通过文本编辑器(如 VSCode)打开`ProgramData\ssh\sshd_config`，修改以下条目(需要管理员权限，也可以把文件复制出去，改完后再覆盖回来)：

```cmd title="sshd_config" :no-line-numbers
  #允许公钥授权访问，确保条目不被注释
  PubkeyAuthentication yes

  #授权文件存放位置，确保条目不被注释
  AuthorizedKeysFile .ssh/authorized_keys

  #可选，关闭密码登录，提高安全性
  PasswordAuthentication no

  #注释掉默认授权文件位置，确保以下条目被注释
  #Match Group administrators
  #       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

  # 注意，OpenSSH 8.8 及以上版本中，默认禁用了使用 SHA-1 哈希算法的 RSA 签名，如果你用的 RSA 密钥就需要加这两行，ed25519 密钥则不需要加
  HostKeyAlgorithms +ssh-rsa
  PubkeyAcceptedAlgorithms +ssh-rsa
```

重启 OpenSSH 服务：在 PowerShell 中执行`Restart-Service sshd`(管理员权限)。\
相关指令：

```powershell :no-line-numbers
  Get-Service sshd  # 查看状态
  Stop-Service sshd # 关闭服务
  Restart-Service sshd # 重启服务
```

### 4.2 OpenWrt 部分

前文提到可以安装`luci-i18n-wol-zh-cn`，它是一个可视化的操作页面，功能实现依赖的是`etherwake`，也就是说只安装`etherwake`用命令行的方式操作就可以了，那样连 OpenWrt 后台页面都不用进。

可以在 OpenWrt 后台页面`软件包`中安装`etherwake`，或者执行命令`opkg install etherwake`。

在 OpenWrt 中，LuCI(Lua Configuration Interface) 是其默认的 Web 界面管理系统，LuCI 本质是 一套用 Lua 编写的 Web 应用逻辑，是一种让 Web 服务器运行外部程序（通常是脚本）的标准接口协议，用来处理动态网页请求。但它并不自带服务器功能，它必须运行在一个 Web 服务器之上，而 uHTTPd 是 OpenWrt 默认提供的轻量级 Web 服务器。

|文件|说明|
|:--:|:--:|
|`/etc/config/luci`|LuCI 的主配置文件，如语言、主题、界面行为等设置|
|`/etc/config/uhttpd`|uHTTPd 的配置文件，控制 Web 服务监听地址、端口、SSL 等|
|`/etc/config/rpcd`|控制 LuCI 使用的 UBUS RPC 权限（例如哪些用户可以远程读写配置）|

`cat /etc/config/uhttpd`查看配置文件：

```bash{8,14}:collapsed-lines=10 title="uhttpd"
config uhttpd 'main' 
        list listen_http '0.0.0.0:80'
        list listen_http '[::]:80'
        # 因为我们主要是内网访问，所以注释掉 443 端口的监听，后面留作他用
        #list listen_https '0.0.0.0:443'
        #list listen_https '[::]:443'
        option redirect_https '0' # http 不要自动重定向到 https
        option home '/www' # Web 根目录，访问静态页面文件的起点
        option rfc1918_filter '1' # 拒绝非私有网段的 IP 访问（例如来自公网 IP），防止 uhttpd 被意外暴露到公网
        option max_requests '50' # 每个进程最多处理 50 个请求
        option max_connections '100' # 最多同时允许 100 个连接
        option cert '/etc/uhttpd.crt'
        option key '/etc/uhttpd.key'
        option cgi_prefix '/cgi-bin' # CGI 请求的路径前缀
        list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua' # 将所有 /cgi-bin/luci 开头的请求交由指定的 Lua 脚本处理，这就是 LuCI 的运行入口。/usr/lib/lua/luci/sgi/uhttpd.lua 是 uHTTPd 专用的 LuCI CGI 启动器
        option script_timeout '3600' # 设置 CGI 脚本最长执行时间为 3600 秒（1 小时），适合处理比较慢的后台任务
        option network_timeout '30' # 客户端连接最长空闲时间（秒）。超过 30 秒没有数据就断开连接
        option http_keepalive '20' # 单个连接最多保持 20 次复用，利于浏览器访问多个资源（JS/CSS）
        option tcp_keepalive '1' # 开启 TCP keepalive，检测空闲连接是否掉线
        option ubus_prefix '/ubus' # 设置 uHTTPd 暴露的 UBUS HTTP API 前缀为 /ubus，用于 RPC 接口
        option interpreter '.sh=/bin/sh' # 定义 .sh 脚本用 /bin/sh 来解释，便于创建简单的 CGI 脚本页面

config cert 'defaults'
        option days '397' # 自签证书有效期 397 天
        option key_type 'ec'
        option bits '256'
        option ec_curve 'P-256'
        option country 'ZZ'
        option state 'Somewhere'
        option location 'Unknown'
        option commonname 'ImmortalWrt'
```

可以看到服务器文件都放在`/www`目录下，cgi 的前缀是`cgi-bin`。因此，为了便捷我我们在`/www/cgi-bin`目录下新增一个文件`wol`：

```bash :collapsed-lines=5 title="wol"
#!/bin/sh

# 主机 MAC
mac="A8:DD:77:CC:00:99"
user="mayee"
host="192.168.0.88"

# 从 URL 路径获取参数
p1=$(echo "$PATH_INFO" | sed 's#^/##')
# 获取 GET 参数
p2=$(echo "$QUERY_STRING" | sed -n 's/.*cmd=\([^&]*\).*/\1/p')

# 优先取路径参数，没有则取 GET 参数，还没有就是空
if [ -n "$p1" ]; then
    cmd="$p1"
elif [ -n "$p2" ]; then
    cmd="$p2"
else
    cmd=""
fi

reply(){
  echo "Content-type: text/plain; charset=utf-8"
  echo "" # http 格式要求必须空一行
  echo "$1"
}

remote_cmd() {
    # -i 用来指定私钥的位置
    ssh -i /root/.ssh/id_rsa $user@$host "$1"
}

case "$cmd" in
  ping)
    # -c 发送一次，-t 超时 10ms(内网环境下 ping 不会有高延迟，10ms 足够长了)。成功返回 1，失败返回 0
    fping -c 1 -t 10 $host > /dev/null && reply 1 || reply 0
    ;;
  sleep)
    result=$(remote_cmd trigger_sleep.bat)
    reply $result
    ;;
  wake)
    # -i 用来指定网卡名，参数可选
    etherwake -i br-lan $mac && reply packet snet
    ;;
  shutdown)
    result=$(remote_cmd shutdown /s /f /t 1) # 或者用 shutdown /p
    reply $result
    ;;
  reboot)
    result=$(remote_cmd shutdown /r /f /t 1)
    reply $result
    ;;
  hibernate)
    result=$(remote_cmd trigger_hibernate.bat)
    reply $result
    ;;
  *)
    reply cmd_error: $cmd
    ;;
esac
```

然后可以通过`http://192.168.0.88/cgi-bin/wol/<cmd>`访问。cmd 可选值：

* `ping`：检测主机是否在线
* `sleep`：睡眠
* `hibernate`：休眠
* `wake`：唤醒
* `shutdown`：关机
* `reboot`：重启

### 4.3 IOS 部分

IOS 快捷指令请求 OpenWrt 脚本的逻辑流程如下：

```flow
st=>start: 快捷指令(IOS)
e=>end: 结束
p=>inputoutput: 发送Ping命令:>http://192.168.0.88/cgi-bin/wol/ping
cond=>condition: 主机在线?
opy=>operation: 菜单(睡/休眠,关机,重启,退出)
opn=>operation: 菜单(唤醒,退出)
st->p(right)->cond
cond(yes, right)->opy->e
cond(no)->opn->e
```

## 结语

上述这套打法可以轻松实现在局域网内，用 iPhone 手机管理主机。可能你会说只能在局域网中使用还是有点鸡肋啊，能不能不在局域网也可以管理主机呢？当然可以，这也是我们下一篇文章的主题：[Lucky内网穿透实践](/article/r9qcnh6l/)。
