如何通过WOL(Wake On Lan)唤醒电脑

demo

话不多说,先看效果视频

痛点

作为一名开发者我们经常需要远程访问自己的笔记本,这样就会遇到一个很大的问题,那就是我们的笔记本必须要一直处于开机状态。那有没有一种情况就是我们需要远程笔记本的时候,先远程笔记本开机,然后再远程笔记本呢?经过我的上网查询发现还真的是有办法远程让笔记本开机,那就是(Wake
On Lan)局域网唤醒。

其实很多BIOS支持通电自动开机,所以就没必要弄这么麻烦,直接买个智能插座就能搞定一切,我这里提供的也只是一种很小众的解决思路,更多的可能是面对笔记本,因为多数笔记本是没有通电自动开机这个功能的吧

什么是(Wake On Lan)局域网唤醒

网络唤醒(Wake-on-LAN,WOL)是一种计算机局域网唤醒技术,使局域网内处于关机或休眠状态的计算机,将状态转换成引导(Boot Loader)或运行状态。无线唤醒(Wake-on-Wireless-LAN,WoWLAN)作为 WOL
的补充技术,使用无线网卡去唤醒计算机。网络唤醒在一般的局域网环境里使用有限广播地址(255.255.255.255)即可,由于路由器都不转发目的地址为有限广播地址的数据报,因此在复杂网络情况下通常使用子网定向广播地址。在局域网外唤醒局域网内特定计算机,可以使用路由器的
DDNS 与端口转发。

在1996年10月,英特尔和 IBM 成立了 Advanced Manageability Alliance。1997年4月,联盟提出了 WOL 技术。这是 WOL 技术的起源,随后各大厂商纷纷推出了自己的 WOL 技术标准。本文所讨论的
WOL 技术是由 AMD 公司提出的 Magic Packet(幻数据包,魔术包)唤醒方式。

开启局域网唤醒

这里我写的可能很不好,大家可以参考一下其他人的方法
如何远程开启你的电脑:WoL的原理和陷阱

1. 支持WOL的有线网卡

现在的有线网卡一般都支持WOL。

注意,一般无线网卡是不能支持WOL,因为在断电情况下,无线网卡与路由器之间的链路就断开了,不同于有线连接,它们之间的链路是没有断开的;

2. 在BIOS中开启wake on lan

这一步非必须,我们需要进入到笔记本的BIOS中查看,以我的为例:

高级 --> 电源管理 --> PCI-E设备唤醒 --> 选项设置为enable

不同电脑进入BIOS界面不一样, 请根据自己的BIOS界面,这里就简答列举几个简单的

3. 配置过程

1. 进入设备管理器

2. 找到有线网卡

3. 右键进入属性中设置,在“高级”——“属性”,开启“关机网络唤醒”和“魔术封包唤醒”;

5. 在“电源管理”,勾选“允许计算机关闭此设备以节约电源”和“允许此设备唤醒计算机”,至于“只允许幻数据包唤醒计算机”,可以勾选也可以不勾选,毕竟我们WOL使用的就是幻数据包。

注意,如果没有以上设置选项或相近选项,就更新下驱动程序,更新到最新的驱动程序仍没有的话,就说明你的网卡不支持WOL了。

测试是否生效

Wake On Lan over the Internet

1. 让笔记本进入睡眠

1
电源 -> 睡眠

2. 唤醒笔记本

win系统获取mac命令 ipconfig -all

这里其实有很多方法都支持,这里不一一列举,就列举两个最简单快捷的

1)点击上述链接,输入对应的IP地址和需要唤醒的笔记本的mac地址,再点击wake up即可

2)或者使用微信小程序,搜网络唤醒即可

总结

通过上面的简单配置就可以让我们的笔记本能够在局域网下远程开机,所以我们可以根据这一个逻辑对其做出优化处理。

原理解析

原理

WOL 技术被提出了将近20年,绝大多数的现代网卡都支持在超低功耗下监听特定的报文,如 ARP。如果设备网卡接收到一个与自己 MAC 地址相同的幻数据包,则网卡会向计算机的电源或主板发出信号以唤醒计算机。大部分的幻数据包在数据链路层(OSI模型第2层)上发送,当发送时,使用广播地址广播到给定的网络上,不使用IP地址(OSI模型第3层)。当然这是绝大部分情况,幻数据包也可以使用特定的 IP 地址进行发送。

简单的用个人的理解来讲述一下。

  1. 当我们的笔记本关机的时候,如果我们开启了wake on lan时,我们的网卡是会处于待机状态
  2. 此时我们通过UDP通信向网卡发送一组幻数据包到网卡上
  3. 网卡就会发送特定的信号唤醒电脑从而实现电脑的开机

什么是幻数据包(Magic Packet)

幻数据包是一个广播帧,包含目标计算机的MAC地址。由于 MAC 地址的唯一性,使数据包可以在网络中被唯一的识别。幻数据包发送通常使用无连接的传输协议,如 UDP ,发送端口为 7 或 9 ,这只是通常做法,没有限制。

幻数据包最简单的构成是6字节的255(FF FF FF FF FF FF
FF),紧接着为目标计算机的48位MAC地址,重复16次,数据包共计102字节。有时数据包内还会紧接着4-6字节的密码信息。这个帧片段可以包含在任何协议中,最常见的是包含在 UDP 中。

例如 MAC 地址为 11 22 33 44 55 66 的目标计算机,幻数据包的格式为:

1
FFFFFFFFFFFF 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 112233445566 [ABABABABABAB(这里为6个字节的密码)]

UDP协议

因为这里需要通过Java程序向我们的网卡发送幻数据包,使用的UDP通信协议。

代码实现

不同的代码有不同的实现方式,这里我们使用java代码作为示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* @auther Lengff
* @time 2021/9/2
* @fileName WakeOnLan
*/
public class WakeOnLan {
private static final int PORT = 9;
private static final String header = "FF:FF:FF:FF:FF:FF";
private static final String concatStr = ":";
private static final String macStr = "1C:7B:1C:2D:7A:0C";
private static final String ipStr = "192.168.1.100";

public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder(header);
for (int i = 0; i < 16; i++) {
stringBuilder.append(concatStr);
stringBuilder.append(macStr);
}

try {
byte[] bytes = getHexBytes(stringBuilder.toString());
InetAddress address = InetAddress.getByName(ipStr);
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, PORT);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
socket.close();
System.out.println("已发送局域网唤醒数据包");
} catch (Exception e) {
System.out.println("无法发送Lan唤醒数据包: " + e);
}
}

private static byte[] getHexBytes(String macStr) throws IllegalArgumentException {
String[] hex = macStr.split("(\\:|\\-)");
byte[] bytes = new byte[hex.length];
try {
for (int i = 0; i < hex.length; i++) {
bytes[i] = (byte) Integer.parseInt(hex[i], 16);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("请使用十六进制的字符");
}
return bytes;
}
}

最终实现

本来以为这个东西挺简单的,三言两语就应该能讲述的清楚,但是我发现还是比较难用文字把整个实现过程讲述清楚,但是我相信上面的代码也足以让大家实现远程开机的demo,只要根据这个demo就能简单快速的做到远程开机,所以这里就简单讲讲我这个视频里面的实现逻辑。

流程图

这里的流程其实是挺简单的,我觉得大家看图就应该能看懂了

前提条件

1. 一台小型服务器

既然要使用这个功能,就必然需要有一个内网的设备来向电脑发送指令,且需要这个设备一直在线; 最理想的其实是路由器,直接通过公网IP来发送指令,但是我们其实很多时候是没有办法拥有公网访问能力,具体可以看看其他大神通过DDNS来实现;
我个人更倾向使用树莓派这些mini服务器来做,既安全而且不依赖网络环境,我的个人博客也是部署在树莓派上面,所以能一举两得

2. 内网穿透工具

如果说是用路由的话且可以访问公网,就只要搞一个DDNS就可以了,但是如果跟我一样使用mini服务器的话,就必须用到一些内网穿透工具;这里也分两种情况

  • 如果有你自己有服务器的话就可以考虑使用 frp内网穿透 或者OPENVPN
    这类反向代理实现内网穿透的工具
  • 如果你没有自己服务器的话就可以使用 ngrok 这类简单粗暴内网穿透工具,我用的比较多的是natapp
    https://www.ngrok.cc/ ,里面有一些收费隧道,价格也不贵,主要是带宽也挺大的,相较于自己买服务器的话,这种的带宽会更大,且更便宜。

3. 代码

我自己临时搞的demo,代码乱糟糟的,有感兴趣的同学可以联系找我那代码,放github就算了,并不是说有多稀罕,主要是自己也是改的别人的开源代码,搞的又很乱,这种东西拿出来开源我觉得实在是没脸。

4. 远程电脑

这里需要单独拿出来讲一讲,这里大概描述一下

  1. 使用内网穿透实现
  • 内网穿透的话就是直接使用系统自带的远程连接来实现远程
  1. 直接使用第三方的远程工具,这里推荐几个我觉得还不错的

  1. 大家用这个功能的时候一定是要在插着网线的情况,且电源没有拔掉的情况下,否则这个是不生效的
  2. 我实测很多次发现一定是开过一次机后关机这个才能用,如果是直接断电了的话这个依旧是不生效的

鸣谢

如何远程开启你的电脑:WoL的原理和陷阱

网络唤醒(WOL)全解指南:原理篇

局域网唤醒(WOL)与远程唤醒教程

网络唤醒原理浅析(Wake On LAN)

一文搞懂TCP与UDP的区别

UDP网络编程DatagramSocket及DatagramPacket的简单使用