Wake On Lan - 理论与实践

0.缘起

我的笔记本和台式机为了能够随时远程使用,一直是开着的,这样太浪费电了。有一个同学给我推荐过这个功能;最近又看到一个同事用到这个。

我之前为了远程开关机,曾经做过一个硬件的reset开关。现在说说这个Wake On Lan的实现,事实上,你可以自己做个小嵌入式的设备来远程唤醒家里的电脑:

1.远程唤醒的机制

  • 这是一个UDP包
  • 不是组播,而是发往255.255.255.255的广播包
  • 一个帧 = 6个连续的0xff + 目标设备的MAC地址*16
  • 端口:9,7(老式设备)

2.实现

2.1 Python远程唤醒代码

import socket

def send_magic_packet(mac_address):
    # 构建 Magic Packet
    mac_bytes = bytes.fromhex(mac_address.replace(':', ''))
    magic_packet = b'\xff' * 6 + mac_bytes * 16

    # 创建 UDP 套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

    # 发送 Magic Packet
    sock.sendto(magic_packet, ('255.255.255.255', 9))
    sock.sendto(magic_packet, ('255.255.255.255', 7))
    sock.close()

# 例子:发送唤醒信号到 MAC 地址为 '00:11:22:33:44:55' 的设备
send_magic_packet('00:11:22:33:44:55')

2.2 嵌入式平台

(如果你家的路由器不支持wake on Lan),或者你没有路由器访问权限:

ESP32

2.3 外网控制

通过mqtt公网服务器中转。代码参见附录A 使用mqtt公网服务器唤醒本地台式机

3.测试

成功了,效果很惊艳。单台设备测试因为udp帧需要从另外一台设备发出,会不太方便,可以在其他设备上设定一个定时任务:

#sleep后面是延时的时间,单位是秒

#nohup不需要保持terminal处于打开状态

#stdout也倒向了/dev/null不会卡死
nohup bash -c 'sleep 90 && python3 wol_test.py' >/dev/null 2>&1 &

3.1 唤醒帧的可行性

执行完这一步,计算机休眠状态可以远程唤醒。

8aeccaf0d3d04e26ba55c8cac1abbcff.png

3.2 BIOS 部分

执行完这一步,机器关机也能唤醒。

b8d2d36808dc469bb1921eacf63d6186.png

4.总结 

基于wol的远程开关机需要如下配置和参数:

  1. 硬件:BIOS打开网卡 wake-on-lan
  2. 系统:网卡PCI-E的电源管理参数修改。
  3. 局域网:要有一个常备的节点能够发送UDP包(如果没有服务器可以使用ESP32写一个程序)
    1. 这里的代码是利用了公司的一个linux服务器
  4. mqtt服务器,可以用免费的公网服务器。
  5. 软件
    1. mqtt服务器连接参数
    2. 手机或者笔记本上的mqtt客户端
    3. mqtt自定义topic
    4. mqtt自定义远程唤醒帧的处理。

附录A 使用mqtt公网服务器唤醒本地台式机

A.1 服务代码

[Unit]
Description=wol service by fengxh
After=network.target

 
[Service]
Type=simple
WorkingDirectory=/home/fengxh
ExecStart=/home/fengxh/daemon_wol_fengxh.py
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target
 

A.2 侦听远程mqtt服务器指定键值,然后调用本地wol唤醒帧的程序

#!/usr/local/bin/python3
# -*- coding: utf-8 -*-
# 获取当前脚本文件所在目录的父目录,并构建相对路径
import os
import sys
current_dir = os.path.dirname(os.path.abspath(__file__))
project_path = os.path.join(current_dir, '..')
sys.path.append(project_path)
sys.path.append(current_dir)

import paho.mqtt.client as mqtt
import subprocess

def is_cmd_wakeup(cmd_line):
    # 要检查的字符串
    text = cmd_line
    # 转换为小写
    text_lower = text.lower()
    
    # 检查是否包含 wakeup key
    if 'xxxxx' in text_lower:
        return True
    else:
        return False

def exec_sh(script_path):
    # 获取当前工作目录
    current_directory = os.getcwd()
    
    # 构造脚本路径
    script_path = os.path.join(current_directory, script_path)
    
    # 执行脚本
    try:
        result = subprocess.run(['bash', script_path], capture_output=True, text=True, check=True)
        print('Script output:', result.stdout)
        print('Script error output:', result.stderr)
    except subprocess.CalledProcessError as e:
        print(f'Error executing script: {e}')

# 处理接收到的消息的回调函数
def on_message(client, userdata, msg):
    print(f"Received message: {msg.payload.decode()} on topic: {msg.topic}")
    if is_cmd_wakeup(msg.payload.decode()):
        exec_sh('./delay3min_wol.sh');

def connected_mqtt_server_loop():
    # MQTT 服务器的配置
    MQTT_BROKER = 'test.mosquitto.org'  # 替换为你的 MQTT 服务器地址
    MQTT_PORT = 1883                   # 通常为 1883
    MQTT_TOPIC = 'xxxxxxxxxxx'          # 可以用uuidgen生成,很难重复
    
    # 创建 MQTT 客户端实例
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
    
    # 设置连接和消息处理的回调函数
    client.on_message = on_message
    
    # 连接到 MQTT 服务器
    client.connect(MQTT_BROKER, MQTT_PORT, 60)
    
    # 订阅指定的 topic
    client.subscribe(MQTT_TOPIC)
    
    # 启动循环以持续接收消息
    client.loop_forever()

if __name__ == "__main__":
    connected_mqtt_server_loop() 

 A.3 调用唤醒代码,不依赖stdio的处理:

里面做了延时的处理等:

nohup bash -c 'sleep 10 && python3 wol_test.py' >/dev/null 2>&1 &

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子正

thanks, bro...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值