Motivation
感谢学校的扩招,原本的两人间硬是魔改成三人间,导致个人书桌面积小到两台笔记本都放不下。无奈之下,淘了一个小桌板,正好能放一台笔记本。但随着考试周的临近,购入若干盒泡面准备进行修仙时才发现 没!地!方!放!泡!面!
无奈之下,只能把Windows本本合上。
反正平时基本上都是远程桌面连上去下迅雷或者推Gal。因此,需要一种机制能够在机器关机的状态下进行远程唤醒,从而进行远程桌面。Google后搜到Wake-on-LAN,是一种在机器处于休眠或关机状态下通过网络进行唤醒的技术。但笔记本没有LAN口,是否能够通过WLAN唤醒呢?继续搜索,发现也是支持的!
Requirement
Wake-on-LAN / Wake-on-WLAN 需要主板和BIOS的支持。
根据Wiki,大概就是机器在休眠或关机时主板和网卡还保持微弱的供电,网卡会监听广播包,并对其进行解析。如果发现符合协议,并且MAC地址就是该网卡的MAC地址,则通知主板进行唤醒。
这种数据包被称为Magic Packet,格式为:
FF FF FF FF FF FF MAC地址
因此通过构造Magic Packet,然后通过UDP进行广播,即可实现唤醒的目的。
经过测试,在我的机器(XPS 9550)上,只能实现从睡眠(S3)和休眠(S4)状态下唤醒,无法从关机(S5)状态唤醒。
Newer Dell system models will not Wake-On-LAN with Deep Sleep Control set to S5
也符合Windows在 https://msdn.microsoft.com/en-us/library/windows/desktop/aa373229(v=vs.85).aspx#wake-on-lan_behavior 的说明:
WOL is supported from sleep (S3) or hibernate (S4). It is not supported from fast startup or soft off (S5) shutdown states. NICs are not armed for wake in these states because users do not expect their systems to wake up on their own.
Implementation
-
进入BIOS中,开启 Wake on WLAN
-
进入Windows中,打开设备管理器,打开无线网卡的属性,在电源管理的tab钩上
允许此设备唤醒计算机
和只允许幻数据包唤醒计算机
后确定。 -
如果需要进入休眠(S4),需要在控制面板的电源选项下点击
更改当前不可用的设置
,然后把休眠
钩上。 -
在网络连接属性处查询无线网卡的MAC地址和局域网的广播地址
- 睡眠/休眠,记得把电源插上
然后在另外一台电脑执行以下脚本,注意把MAC和BROADCAST改成你自己的:
# !/usr/bin/env python # -*- coding: utf-8 -*- # # FileName: wol.py # Author: binss # Create: 2017-06-04 22:32:48 # Description: Ref: https://github.com/bentasker/Wake-On-Lan-Python # import socket import struct import time MAC = "60-6D-C4-C6-30-48" BROADCAST = "192.168.1.255" def main(): if len(MAC) != 17: raise ValueError("MAC address should be set as form 'XX-XX-XX-XX-XX-XX'") mac_address = MAC.replace("-", '') data = ''.join(['FFFFFFFFFFFF', mac_address * 20]) send_data = b'' # Split up the hex values and pack. for i in range(0, len(data), 2): send_data = b''.join([send_data, struct.pack('B', int(data[i: i + 2], 16))]) # Broadcast try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.sendto(send_data, (BROADCAST, 7)) time.sleep(1) sock.sendto(send_data, (BROADCAST, 7)) time.sleep(1) sock.sendto(send_data, (BROADCAST, 7)) print("Done") except Exception as e: print(e) if __name__ == '__main__': main()
Troubleshoot执行后就可以发现机器被唤醒了。
为什么休眠后发现机器立刻被唤醒了?
通过powercfg -devicequery wake_armed
发现唤醒设备除了无线网卡意外还有一个远程桌面鼠标设备,不知道是干啥的,把鼠标拔掉后解决。