使用 C# 进行 LAN 唤醒

发布于 2024-07-21 16:47:01 字数 794 浏览 6 评论 0原文

使用 C# 实现 LAN 唤醒的最佳方法是什么?

LAN 环境(而不是互联网)中的计算机需要该功能。 该方法需要足够强大才能解决防火墙和其他此类问题。 另外,对于不支持此功能或禁用此功能的系统,是否有替代方案?

主要目标 - 通过 LAN 唤醒机器(从关闭/休眠状态) - 这是使用 C# 进行编程。

请指导。

PS:我遇到过以下内容:

  1. http://blog.memos.cz/index.php/team/2008/06/12/wake-on-lan-in-csharp
  2. http://community.bartdesmet.net/blogs/bart/archive/2006/04/02/3858.aspx
  3. http://www.codeproject.com/KB/IP/cswol.aspx

但是,我对此很陌生,因此无法确定解决方案是否足够全面。 如果有人可以推荐遵循上述任何一篇文章,那将会有所帮助。

What's the best way going forward to implement Wake on LAN using C#?

The functionality is needed for machines in a LAN environment (and not over the internet). The method needs to be robust enough to take care of firewalls and other such issues. Also, for systems not supporting this functionality, or having it disabled, is there an alternative?

The primary objective - wake up machines (from shutdown/hibernate state) over the LAN - this is to be programmed using C#.

Please guide.

PS: I've come across the following:

  1. http://blog.memos.cz/index.php/team/2008/06/12/wake-on-lan-in-csharp
  2. http://community.bartdesmet.net/blogs/bart/archive/2006/04/02/3858.aspx
  3. http://www.codeproject.com/KB/IP/cswol.aspx

However, I'm new to this and hence couldn't figure if the solutions were comprehensive enough. If someone could recommend following either of the above articles, that'd help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

那一片橙海, 2024-07-28 16:47:01

我知道,这是一个很老的问题,但仍然有效。 由于我在接受的答案中没有看到任何 C#,因此我编写了自己的“Wake On Lan”代码。

我的目标是创建一个通用且简单的LAN 唤醒类,它:

  • 适用于 ipv4ipv6 和 < em>双栈。
  • 与连接到不同网络(两台计算机)的一个或多个网卡 (NICS) 配合使用。
  • 适用于任何标准十六进制格式的 macaddress
  • 使用多播(在 Windows 中使用多个 NIC 时广播会出现问题,并且在使用 ipv6 时不支持广播)。

如何使用:

您所需要的只是您想要唤醒的计算机上的有线网卡的MAC地址。 任何标准的十六进制表示都可以。 然后像这样调用代码:

string mac = "01-02-03-04-05-06";
await WOL.WakeOnLan(mac);

这是类:

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

public static class WOL
{

    public static async Task WakeOnLan(string macAddress)
    {
        byte[] magicPacket = BuildMagicPacket(macAddress);
        foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where((n) =>
            n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up))
        {
            IPInterfaceProperties iPInterfaceProperties = networkInterface.GetIPProperties();
            foreach (MulticastIPAddressInformation multicastIPAddressInformation in iPInterfaceProperties.MulticastAddresses)
            {
                IPAddress multicastIpAddress = multicastIPAddressInformation.Address;
                if (multicastIpAddress.ToString().StartsWith("ff02::1%", StringComparison.OrdinalIgnoreCase)) // Ipv6: All hosts on LAN (with zone index)
                {
                    UnicastIPAddressInformation unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetworkV6 && !u.Address.IsIPv6LinkLocal).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                        break;
                    }
                }
                else if (multicastIpAddress.ToString().Equals("224.0.0.1")) // Ipv4: All hosts on LAN
                {
                    UnicastIPAddressInformation unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetwork && !iPInterfaceProperties.GetIPv4Properties().IsAutomaticPrivateAddressingActive).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                        break;
                    }
                }
            }
        }
    }

    static byte[] BuildMagicPacket(string macAddress) // MacAddress in any standard HEX format
    {
        macAddress = Regex.Replace(macAddress, "[: -]", "");
        byte[] macBytes = new byte[6];
        for (int i = 0; i < 6; i++)
        {
            macBytes[i] = Convert.ToByte(macAddress.Substring(i * 2, 2), 16);
        }

        using (MemoryStream ms = new MemoryStream())
        {
            using (BinaryWriter bw = new BinaryWriter(ms))
            {
                for (int i = 0; i < 6; i++)  //First 6 times 0xff
                {
                    bw.Write((byte)0xff);
                }
                for (int i = 0; i < 16; i++) // then 16 times MacAddress
                {
                    bw.Write(macBytes);
                }
            }
            return ms.ToArray(); // 102 bytes magic packet
        }
    }

    static async Task SendWakeOnLan(IPAddress localIpAddress, IPAddress multicastIpAddress, byte[] magicPacket)
    {
        using (UdpClient client = new UdpClient(new IPEndPoint(localIpAddress, 0)))
        {
            await client.SendAsync(magicPacket, magicPacket.Length, multicastIpAddress.ToString(), 9);
        }
    }
}

工作原理:

该代码的工作原理是枚举所有处于“启动”状态并连接到您的网络的网卡(通常是只有一个)。 它将使用多播将“魔法数据包”发送到所有连接的网络,多播适用于 ipv4 和 ipv6(不用担心淹没您的网络,它只有 102 字节)。

要工作,您想要唤醒的计算机必须具有有线连接(无线计算机无法被唤醒,因为它们在关闭时未连接到任何网络)。 发送数据包的计算机可以进行无线连接。

防火墙通常没有问题,因为计算机已关闭,因此防火墙未处于活动状态。

您必须确保计算机的 BIOS 和网卡上“局域网唤醒”启用

更新.Net 6(以及错误修复):

修复了一个错误,如果 Ipv6 在发送数据包的计算机上运行,​​但在应该被唤醒的计算机上运行,​​则它不会尝试 Ipv4(这已在上面的代码中修复)。

下面是在 .Net 6 上运行的代码(借用了 @Oskar Sjôberg 的一些代码) - 隐式使用已打开

using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;

public static class WOL
{
    public static async Task WakeOnLan(string macAddress)
    {
        byte[] magicPacket = BuildMagicPacket(macAddress);
        foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where((n) =>
            n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up))
        {
            IPInterfaceProperties iPInterfaceProperties = networkInterface.GetIPProperties();
            foreach (MulticastIPAddressInformation multicastIPAddressInformation in iPInterfaceProperties.MulticastAddresses)
            {
                IPAddress multicastIpAddress = multicastIPAddressInformation.Address;
                if (multicastIpAddress.ToString().StartsWith("ff02::1%", StringComparison.OrdinalIgnoreCase)) // Ipv6: All hosts on LAN (with zone index)
                {
                    UnicastIPAddressInformation? unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetworkV6 && !u.Address.IsIPv6LinkLocal).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                    }
                }
                else if (multicastIpAddress.ToString().Equals("224.0.0.1")) // Ipv4: All hosts on LAN
                {
                    UnicastIPAddressInformation? unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetwork && !iPInterfaceProperties.GetIPv4Properties().IsAutomaticPrivateAddressingActive).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                    }
                }
            }
        }
    }

    static byte[] BuildMagicPacket(string macAddress) // MacAddress in any standard HEX format
    {
        macAddress = Regex.Replace(macAddress, "[: -]", "");
        byte[] macBytes = Convert.FromHexString(macAddress);

        IEnumerable<byte> header = Enumerable.Repeat((byte)0xff, 6); //First 6 times 0xff
        IEnumerable<byte> data = Enumerable.Repeat(macBytes, 16).SelectMany(m => m); // then 16 times MacAddress
        return header.Concat(data).ToArray();
    }

    static async Task SendWakeOnLan(IPAddress localIpAddress, IPAddress multicastIpAddress, byte[] magicPacket)
    {
        using UdpClient client = new(new IPEndPoint(localIpAddress, 0));
        await client.SendAsync(magicPacket, magicPacket.Length, new IPEndPoint(multicastIpAddress, 9));
    }
}

Very old question, I know, but still valid. Since I didn't see any C# in the accepted answer, I wrote my own 'Wake On Lan' code.

My goal was to make a universal and easy Wake On Lan class that:

  • works with ipv4, ipv6 and dual-stack.
  • works with one or multiple network cards (NICS) connected to different networks (both computers).
  • works with macaddress in any standard hex format.
  • works using multicast (broadcast is buggy in Windows when using multiple NICs and is not supported when using ipv6).

How to use:

All you need, is the MAC address of the wired nic on the computer you wish to wake up. Any standard hex representation will do. Then call the code like this:

string mac = "01-02-03-04-05-06";
await WOL.WakeOnLan(mac);

Here's the class:

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

public static class WOL
{

    public static async Task WakeOnLan(string macAddress)
    {
        byte[] magicPacket = BuildMagicPacket(macAddress);
        foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where((n) =>
            n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up))
        {
            IPInterfaceProperties iPInterfaceProperties = networkInterface.GetIPProperties();
            foreach (MulticastIPAddressInformation multicastIPAddressInformation in iPInterfaceProperties.MulticastAddresses)
            {
                IPAddress multicastIpAddress = multicastIPAddressInformation.Address;
                if (multicastIpAddress.ToString().StartsWith("ff02::1%", StringComparison.OrdinalIgnoreCase)) // Ipv6: All hosts on LAN (with zone index)
                {
                    UnicastIPAddressInformation unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetworkV6 && !u.Address.IsIPv6LinkLocal).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                        break;
                    }
                }
                else if (multicastIpAddress.ToString().Equals("224.0.0.1")) // Ipv4: All hosts on LAN
                {
                    UnicastIPAddressInformation unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetwork && !iPInterfaceProperties.GetIPv4Properties().IsAutomaticPrivateAddressingActive).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                        break;
                    }
                }
            }
        }
    }

    static byte[] BuildMagicPacket(string macAddress) // MacAddress in any standard HEX format
    {
        macAddress = Regex.Replace(macAddress, "[: -]", "");
        byte[] macBytes = new byte[6];
        for (int i = 0; i < 6; i++)
        {
            macBytes[i] = Convert.ToByte(macAddress.Substring(i * 2, 2), 16);
        }

        using (MemoryStream ms = new MemoryStream())
        {
            using (BinaryWriter bw = new BinaryWriter(ms))
            {
                for (int i = 0; i < 6; i++)  //First 6 times 0xff
                {
                    bw.Write((byte)0xff);
                }
                for (int i = 0; i < 16; i++) // then 16 times MacAddress
                {
                    bw.Write(macBytes);
                }
            }
            return ms.ToArray(); // 102 bytes magic packet
        }
    }

    static async Task SendWakeOnLan(IPAddress localIpAddress, IPAddress multicastIpAddress, byte[] magicPacket)
    {
        using (UdpClient client = new UdpClient(new IPEndPoint(localIpAddress, 0)))
        {
            await client.SendAsync(magicPacket, magicPacket.Length, multicastIpAddress.ToString(), 9);
        }
    }
}

How it works:

The code works by enumerating all network cards that are 'up' and connected to your network (that's usually just one). It will send out the 'magic packet' to all your connected networks using multicast, which works with both ipv4 and ipv6 (don't worry about flooding your network, it's only 102 bytes).

To work, the computer, you want to wake up, must have a wired connection (wireless computers can't be woken up, since they aren't connected to any network, when they are off). The computer, that sends the packet, can be wireless connected.

Firewalls are usually no problem, since the computer is off and hence the firewall is not active.

You must make sure that 'Wake on lan' is enabled in the computer's BIOS and on the network card.

Update for .Net 6 (and a bug fix):

Fixed a bug, where if Ipv6 was functioning on the computer that sends the packet but not on the one, that should be awakened, then it would not try Ipv4 (this is fixed in the code above).

Here's the code that works on .Net 6 (borrowed some of @Oskar Sjôberg's code) - implicit usings turned on:

using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.RegularExpressions;

public static class WOL
{
    public static async Task WakeOnLan(string macAddress)
    {
        byte[] magicPacket = BuildMagicPacket(macAddress);
        foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where((n) =>
            n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up))
        {
            IPInterfaceProperties iPInterfaceProperties = networkInterface.GetIPProperties();
            foreach (MulticastIPAddressInformation multicastIPAddressInformation in iPInterfaceProperties.MulticastAddresses)
            {
                IPAddress multicastIpAddress = multicastIPAddressInformation.Address;
                if (multicastIpAddress.ToString().StartsWith("ff02::1%", StringComparison.OrdinalIgnoreCase)) // Ipv6: All hosts on LAN (with zone index)
                {
                    UnicastIPAddressInformation? unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetworkV6 && !u.Address.IsIPv6LinkLocal).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                    }
                }
                else if (multicastIpAddress.ToString().Equals("224.0.0.1")) // Ipv4: All hosts on LAN
                {
                    UnicastIPAddressInformation? unicastIPAddressInformation = iPInterfaceProperties.UnicastAddresses.Where((u) =>
                        u.Address.AddressFamily == AddressFamily.InterNetwork && !iPInterfaceProperties.GetIPv4Properties().IsAutomaticPrivateAddressingActive).FirstOrDefault();
                    if (unicastIPAddressInformation != null)
                    {
                        await SendWakeOnLan(unicastIPAddressInformation.Address, multicastIpAddress, magicPacket);
                    }
                }
            }
        }
    }

    static byte[] BuildMagicPacket(string macAddress) // MacAddress in any standard HEX format
    {
        macAddress = Regex.Replace(macAddress, "[: -]", "");
        byte[] macBytes = Convert.FromHexString(macAddress);

        IEnumerable<byte> header = Enumerable.Repeat((byte)0xff, 6); //First 6 times 0xff
        IEnumerable<byte> data = Enumerable.Repeat(macBytes, 16).SelectMany(m => m); // then 16 times MacAddress
        return header.Concat(data).ToArray();
    }

    static async Task SendWakeOnLan(IPAddress localIpAddress, IPAddress multicastIpAddress, byte[] magicPacket)
    {
        using UdpClient client = new(new IPEndPoint(localIpAddress, 0));
        await client.SendAsync(magicPacket, magicPacket.Length, new IPEndPoint(multicastIpAddress, 9));
    }
}
长梦不多时 2024-07-28 16:47:01

对于 WOL 问题,您必须澄清三个问题才能使其正常工作:

  1. 通过以太网电缆发送 WOL
  2. 配置您的 PC 以侦听此类问题
    一个数据包并唤醒
  3. 确保数据包来自
    发送者到接收者(防火墙,

正如您已经在网上发现的那样,对于用 C# 编程的第一个问题,有几种现有的解决方案(在浏览完您的链接后,我将从第一个开始)

第二个是只能通过配置网络适配器来实现的。 只需打开设备管理器并查看网络适配器的属性,看看是否存在此类选项以及是否可以启用它。 这是无法编程的,因为每个网络适配器都有该功能的另一种实现以及如何启用它。

第三个问题也无法用C#解决。 这是一个纯粹的网络问题,您必须配置路由器、网关、ID 系统等以允许此类数据包并让它从发送方流向接收方。 事实上,WOL 数据包始终是广播数据包 (dest-ip 255.255.255.255),它不会离开您的本地网络,并且始终会从路由器、网关或网络之间的任何其他网桥(例如 VPN、 ETC。)。

最后但并非最不重要的一点是,我只是提醒您,第一个问题可以分为一些较小的数据包,但据我所知,这些问题都受到您提供的链接的限制。

For the WOL problem you have to clarify three problems to get it to work:

  1. Send a WOL over the ethernet cable
  2. Configure your PC to listen for such
    a packet and wake up
  3. Make sure the packet will come from
    sender to receiver (firewall,
    gateways, etc.)

As you already found on the net there are existing several solutions for the first problem programmed in C# (and after skimming your links, I would start with the first one).

The second one is something you can only achieve by configuring your network adapter. Just open the device manager and take a look into the properties of your network adapter, if such an option exists and if you can enable it. This can't be programmed, due to the fact that every network adapter has another implementation of that function and how it can be enabled.

The third problem can't also be solved by C#. It is a pure network problem, where you have to configure your router, gateways, ids-systems, etc. to allow such a packet and let it flow from sender to receiver. Due to the fact, that a WOL packet is always a broadcast packet (dest-ip 255.255.255.255) it won't leave your local network and will always be dropped from router, gateways or any other bridge between to networks (e.g. vpns, etc.).

Last but not least, I will just remind you, that the first problem can be divided into some smaller packets but as far as I could see these problems are all capped by the links you provided.

静谧幽蓝 2024-07-28 16:47:01

我正在尝试 Poul Bak 的答案,但无法唤醒我的目标计算机。 验证第三方应用程序后,WakeMeOnLan 实际上能够唤醒我的目标计算机,我编写了这段对我有用的代码:

void SendWakeOnLan(PhysicalAddress target)
{   
    var header = Enumerable.Repeat(byte.MaxValue, 6);
    var data = Enumerable.Repeat(target.GetAddressBytes(), 16).SelectMany(mac => mac);

    var magicPacket = header.Concat(data).ToArray();
    
    using var client = new UdpClient();

    client.Send(magicPacket, magicPacket.Length, new IPEndPoint(IPAddress.Broadcast, 9));
}

用法:

只需传入目标计算机的 mac 地址,如下所示:

SendWakeOnLan(PhysicalAddress.Parse("0A-0B-0C-0D-0E-0F"));

我认为这个答案与 Poul Bak 的答案之间的主要区别在于,该代码使用 IPv4 广播而不是 IPv4 上的多播IPv4/IPv6,也许我的网络设备无法正确处理/设置多播。

I was trying Poul Bak´s answer but was unable to wake my target computer. After verifying that a third party application, WakeMeOnLan in fact was able to wake my target computer, I wrote this code that worked for me:

void SendWakeOnLan(PhysicalAddress target)
{   
    var header = Enumerable.Repeat(byte.MaxValue, 6);
    var data = Enumerable.Repeat(target.GetAddressBytes(), 16).SelectMany(mac => mac);

    var magicPacket = header.Concat(data).ToArray();
    
    using var client = new UdpClient();

    client.Send(magicPacket, magicPacket.Length, new IPEndPoint(IPAddress.Broadcast, 9));
}

Usage:

Simply by passing in the target computers mac address like so:

SendWakeOnLan(PhysicalAddress.Parse("0A-0B-0C-0D-0E-0F"));

I think the main difference between this answer and Poul Bak´s answer is that this code is using broadcast over IPv4 instead of multicast on IPv4/IPv6, and maybe my network equipment is not handling/setup to do multicast correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文