手搓开机棒:使用.Net nanoFramework 实现WOL唤醒远程开机

本文将介绍如何使用ESP32硬件制作一个开机棒,通过.Net nanoFramework实现WOL(Wake-on-LAN)功能,发送WOL数据包来唤醒远程计算机。

1. 背景

在之前的文章中,我们介绍了如何使用.Net nanoFramework相关的库来实现一些功能,比如读取传感器数据、控制LED灯、OLED显示等。也介绍了通过.NET实现WOL(Wake-on-LAN)功能,并在NAS或通过ASP.NET进行部署。可以能有的小伙伴没有NAS或者服务器,但是有ESP32硬件,那么我们可以使用ESP32硬件制作一个开机棒,通过发送WOL数据包来唤醒远程计算机。在这篇文章中,我们将介绍如何使用.Net nanoFramework实现WOL(Wake-on-LAN)功能,通过发送WOL数据包来唤醒远程计算机。

相关文章:

以上的文章包含了基本的WOL相关实现和介绍以及.Net nanoFramework基础开发知识,如果你对.Net nanoFramework不熟悉,建议先阅读这些文章,可以帮助你更好的读懂本文的内容。

2. 实现方法

在工作状态灯的应用文章中,我们介绍了一个 ProjectImprovWifi 的示例项目,这个示例包含了基本的工作状态灯控制,我们可以基于这个项目框架来快速实现WOL功能。

WOL的实现原理是通过网络发送一个特定的数据包(Magic Packet)到目标计算机的MAC地址,目标计算机就会被唤醒。在.Net nanoFramework中,我们可以使用 nanoFramework.System.Net.Sockets.UdpClient 库来实现UDP数据包的发送。

下面的代码示例演示了如何使用.Net nanoFramework实现WOL功能,这里需要注意的是,因为环境的限制,UdpClient 的使用,以及没有Replace方法等问题,需要我们对之前.NET的代码进行一些修改:

csharp 复制代码
using System;
using System.Net;
using System.Net.Sockets;

namespace WakeOnLan_ESP32
{
    internal class WakeOnLan
    {

        internal static void Send(string macAddress)
        {
            byte[] magicPacket = CreateMagicPacket(macAddress);
            SendMagicPacket(magicPacket);
        }

        static byte[] CreateMagicPacket(string macAddress)
        {
            byte[] macBytes = ParseMacAddress(macAddress);
            byte[] magicPacket = new byte[6 + (6 * 16)];

            for (int i = 0; i < 6; i++)
            {
                magicPacket[i] = 0xFF;
            }

            for (int i = 6; i < magicPacket.Length; i += 6)
            {
                Array.Copy(macBytes, 0, magicPacket, i, 6);
            }

            return magicPacket;
        }

        static byte[] ParseMacAddress(string macAddress)
        {
            if (macAddress.Length == 17)
            {
                macAddress = macAddress.Substring(0, 2) + macAddress.Substring(3, 2) + macAddress.Substring(6, 2) + macAddress.Substring(9, 2) + macAddress.Substring(12, 2) + macAddress.Substring(15, 2);
            }

            if (macAddress.Length != 12)
            {
                throw new ArgumentException("Invalid MAC address.");
            }

            byte[] macBytes = new byte[6];

            for (int i = 0; i < 6; i++)
            {
                macBytes[i] = Convert.ToByte(macAddress.Substring(i * 2, 2), 16);
            }

            return macBytes;
        }

        static void SendMagicPacket(byte[] magicPacket)
        {
            UdpClient udpClient = new UdpClient();
            udpClient.Connect(IPAddress.Broadcast, 9);
            udpClient.Send(magicPacket);
            udpClient.Close();
            Console.WriteLine("Magic packet sent.");
        }

    }
}

在这个示例中,我们定义了一个 WakeOnLan 类,其中包含了 Send 方法,用于发送WOL数据包。在 Send 方法中,我们首先调用 CreateMagicPacket 方法创建一个Magic Packet,然后调用 SendMagicPacket 方法发送数据包。

3. 页面设计

完成了核心的唤醒代码后,我们需要让用户输入目标计算机的MAC地址,然后点击按钮发送WOL数据包。这里我们可以使用OLED显示屏来显示提示信息和用户输入的MAC地址。这里可以使用 ESP32 创建一个Web服务器,通过浏览器输入MAC地址,然后发送WOL数据包。

这里我们需要用到nanoFramework.System.Net.Http库,这个库可以用来创建一个简单的Web服务器,接收用户的输入,然后发送WOL数据包。

csharp 复制代码
string responseString =
    "<HTML><HEAD>" +
    "<meta name='viewport' content='width=device-width, initial-scale=1'>" +
    "<style>" +
    "body { font-family: Arial, sans-serif; margin: 20px;text-align: center;}" +
    "h2 { color: #333; }" +
    "form { margin-top: 20px; }" +
    "input[type='text'] { padding: 10px; border: 1px solid #ccc; border-radius:4px 0 0 4px; width: 250px; }" +
    "input[type='submit'] { padding: 10px 20px; border: none; border-radius:0 4px 4px 0; background-color: #4CAF50; color: white; cursor: pointer; }" +
    "input[type='submit']:hover { background-color: #45a049; }" +
    "p { line-height: 1.6; }" +
    "a { color: #1E90FF; text-decoration: none; }" +
    "a:hover { text-decoration: underline; }" +
    "#mac-list { margin: 20px auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); width: 100%; max-width: 350px; }" +
    "#mac-list ul { list-style-type: none; padding: 0; }" +
    "#mac-list li { padding: 5px 0; border-bottom: 1px solid #ccc; }" +
    "</style>" +
    "</HEAD><BODY>" +
    "<h2>ESP32 WakeOnLan</h2>" +
    "<p>Click the button to send a Wake On LAN packet.</p>" +
    "<form method='get' action='/wol' οnsubmit='return validateAndFormatMac()'>" +
    "<input type='text' id='mac' name='mac' value='' />" +
    "<input type='submit' value='Wake On LAN' />" +
    "</form>" +
    "<div id='mac-list'>" +
    "<h3>Stored MAC Addresses</h3>" +
    "<ul id='list'></ul>" +
    "</div>" +
    "<script>" +
    "function validateAndFormatMac() {" +
    "    var macInput = document.getElementById('mac');" +
    "    var mac = macInput.value;" +
    "    var macRegex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;" +
    "    if (!macRegex.test(mac)) {" +
    "        alert('Invalid MAC address format. Please use XX:XX:XX:XX:XX:XX or XX-XX-XX-XX-XX-XX.');" +
    "        return false;" +
    "    }" +
    "    mac = mac.replace(/[:-]/g, '');" +
    "    macInput.value = mac;" +
    "    storeMac(mac);" +
    "    return true;" +
    "}" +
    "function storeMac(mac) {" +
    "    var macs = JSON.parse(localStorage.getItem('macs')) || [];" +
    "    macs.push(mac);" +
    "    localStorage.setItem('macs', JSON.stringify(macs));" +
    "    displayMacs();" +
    "}" +
    "function displayMacs() {" +
    "    var macs = JSON.parse(localStorage.getItem('macs')) || [];" +
    "    var list = document.getElementById('list');" +
    "    list.innerHTML = '';" +
    "    macs.forEach(function(mac) {" +
    "        var li = document.createElement('li');" +
    "        var a = document.createElement('a'); " +
    "        a.href = '/wol?mac=' + mac;" +
    "        a.textContent = mac;" +
    "        li.appendChild(a);" +
    "        list.appendChild(li);" +
    "    });" +
    "}" +
    "document.addEventListener('DOMContentLoaded', displayMacs);" +
    "</script>" +
    "</BODY></HTML>";

byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

HttpListener listener = new("http", 80);

listener.Start();

这里的网页内容是硬编码在代码中的,我们可以通过 HttpListener 类来创建一个简单的Web服务器,然后监听用户的输入。用户输入的MAC地址会被存储在本地存储中,然后显示在页面的底部。用户可以点击列表中的MAC地址来发送WOL数据包。

启动服务后,我们简单的使用一个死循环来监听用户的请求,通过判断URL是否包含/wol?mac=来发送WOL数据包,然后返回一个JSON格式的响应。

csharp 复制代码
while (true)
{
    try
    {
        HttpListenerContext context = listener.GetContext();
        var url = context.Request.RawUrl;
        HttpListenerResponse response = context.Response;

        if (url.StartsWith("/wol?mac="))
        {
            var macAddress = url.Substring(9);
            Console.WriteLine($"WOL packet sent to {macAddress}");
            WakeOnLan.Send(macAddress);

            // 输出json格式
            response.ContentType = "application/json";
            var json = System.Text.Encoding.UTF8.GetBytes("{\"status\":\"ok\"}");
            response.ContentLength64 = json.Length;
            response.OutputStream.Write(json, 0, json.Length);
        }
        else
        {
            // 输出默认页面
            response.ContentLength64 = buffer.Length;
            response.OutputStream.Write(buffer, 0, buffer.Length);
        }
        context.Response.Close();
        Console.WriteLine("Web response sent");
        context.Close();
    }
    catch (Exception ex)
    {
        Console.WriteLine("* Error getting context: " + ex.Message + "\r\nSack = " + ex.StackTrace);
    }
}

4. 使用方法

在完成了代码的编写后,我们可以将代码部署到ESP32上。首次使用需要先完成 Improv 蓝牙配网,这里可以通过"Improv 蓝牙配网"微信小程序或者 Improv 官网来完成。建议是使用小程序,这样可以在配网成功后,可以直接显示ESP32的IP地址。

然后通过浏览器访问ESP32的IP地址,即可看到硬件的 Web 服务,可以在页面上输入MAC地址,然后点击按钮发送WOL数据包。

5. 总结

在这篇文章中,我们介绍了如何使用.Net nanoFramework实现WOL功能,通过发送WOL数据包来唤醒远程计算机。我们首先实现了核心的WOL代码,然后通过Web服务器来接收用户的输入,最后发送WOL数据包。这样可以方便我们通过浏览器来发送WOL数据包,实现远程开机的功能。

文章介绍的相关代码已开源在GitHub,欢迎查看和收藏。希望这篇文章对你有所帮助,如果有任何问题或建议,欢迎在评论区留言。

如果你对ESP32版本的WOL感兴趣,可以关注"桑榆肖物",回复"网络唤醒"获取完整源码。

Github 主页:https://github.com/sangyuxiaowu?WT.mc_id=DT-MVP-5005195

相关推荐
我先去打把游戏先20 分钟前
ESP32学习笔记(基于IDF):ESP32连接MQTT服务器
服务器·笔记·单片机·嵌入式硬件·学习·esp32
追逐时光者6 小时前
一个基于 .NET 开源、功能强大的分布式微服务开发框架
后端·.net
笺上知微7 小时前
Serilog基于Seq开源框架实现日志分析
.net
百锦再7 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
CodeCraft Studio8 小时前
【能源与流程工业案例】KBC借助TeeChart 打造工业级数据可视化平台
java·信息可视化·.net·能源·teechart·工业可视化·工业图表
一个帅气昵称啊8 小时前
使用微软Agent Framework .NET构建智能代理应用
microsoft·flask·.net
一个天蝎座 白勺 程序猿10 小时前
深度解析:通过ADO.NET驱动Kdbndp高效连接与操作Kingbase数据库
数据库·.net·wpf·kingbase·金仓数据库
时光追逐者11 小时前
一个使用 WPF 开发的 Diagram 画板工具(包含流程图FlowChart,思维导图MindEditor)
c#·.net·wpf·流程图
我是唐青枫11 小时前
C#.NET FluentValidation 全面解析:优雅实现对象验证
c#·.net
VB.Net11 小时前
VB.Net循序渐进(第二版)
开发语言·.net·vb.net