Qt5.15.2 C++ 使用 UDP 发送 Wake-on-LAN(WOL)魔术包唤醒远端计算机

24 01月
作者:cinjep|分类:应用笔记
#include <QCoreApplication>
#include <QUdpSocket>
#include <QHostAddress>
#include <QByteArray>
#include <QDebug>
#include <QStringList>

// 将 MAC 地址字符串(如 "AA:BB:CC:DD:EE:FF")转换为 QByteArray
QByteArray macAddressToByteArray(const QString &macStr)
{
    QByteArray mac;
    QStringList parts = macStr.split(':');
    if (parts.size() != 6) {
        qWarning() << "Invalid MAC address format!";
        return QByteArray();
    }

    for (const QString &part : parts) {
        bool ok;
        int byte = part.toInt(&ok, 16);
        if (!ok || byte < 0 || byte > 255) {
            qWarning() << "Invalid MAC byte:" << part;
            return QByteArray();
        }
        mac.append(static_cast<char>(byte));
    }
    return mac;
}

// 发送 Wake-on-LAN 魔术包
bool sendWakeOnLan(const QString &macAddress, const QHostAddress &broadcastAddress = QHostAddress::Broadcast, quint16 port = 9)
{
    QByteArray macBytes = macAddressToByteArray(macAddress);
    if (macBytes.isEmpty() || macBytes.size() != 6) {
        qWarning() << "Invalid MAC address.";
        return false;
    }

    // 构造 Magic Packet:
    // 6 bytes of 0xFF followed by 16 repetitions of the MAC address
    QByteArray magicPacket;
    magicPacket.fill(0xFF, 6);
    for (int i = 0; i < 16; ++i) {
        magicPacket.append(macBytes);
    }

    QUdpSocket udpSocket;
    udpSocket.setSocketOption(QAbstractSocket::MulticastTtlOption, 255); // 可选:设置 TTL

    bool success = udpSocket.writeDatagram(magicPacket, broadcastAddress, port) == magicPacket.size();

    if (success) {
        qDebug() << "Magic packet sent to" << macAddress << "at" << broadcastAddress.toString() << ":" << port;
    } else {
        qWarning() << "Failed to send magic packet:" << udpSocket.errorString();
    }

    udpSocket.close();
    return success;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // 示例:替换为你想唤醒的设备的 MAC 地址
    QString targetMac = "AA:BB:CC:DD:EE:FF"; // ←← 修改这里!

    // 可选:指定广播地址(通常 255.255.255.255 即可)
    QHostAddress broadcastAddr("255.255.255.255");

    // 发送魔术包(默认端口 9)
    sendWakeOnLan(targetMac, broadcastAddr, 9);

    return 0;
}



注意事项:

  1. 目标计算机必须支持并启用 Wake-on-LAN(通常在 BIOS/UEFI 和网卡驱动中设置)。

  2. 发送方和目标必须在同一局域网(除非路由器支持转发 WOL 包)。

  3. 防火墙不能阻止 UDP 端口 7/9 的广播

  4. MAC 地址格式必须为 XX:XX:XX:XX:XX:XX(不区分大小写,也可用 -,但需修改解析逻辑)。

  5. 在某些系统上,可能需要管理员权限才能发送广播包(尤其是 Windows)。


使用子网定向广播地址

如果你知道目标计算机所在的子网(例如 192.168.1.0/24),可以将广播地址设为 192.168.1.255,而不是全局广播 255.255.255.255。这在某些网络环境中更可靠(尤其当路由器隔离了全局广播)。

修改后的代码(指定子网广播地址):

替换 broadcastAddr
QHostAddress broadcastAddr("192.168.1.255"); // ← 替换为你的子网广播地址
sendWakeOnLan(targetMac, broadcastAddr, 9);

为什么不能用 TCP?

TCP 是一种 面向连接、基于 IP 层(网络层)的可靠传输协议,而 WOL 的工作机制完全依赖于 数据链路层(Layer 2)的广播帧。以下是关键原因:

1. 目标设备在关机/睡眠状态下没有 TCP/IP 协议栈运行

当计算机关闭或处于 S3/S4/S5 睡眠状态时:

操作系统已停止运行。

TCP/IP 协议栈不工作,无法监听任何 TCP 端口。

网卡仅以极低功耗运行,只监听特定格式的以太网帧(即魔术包)。

TCP 需要三次握手、端口监听、ACK 确认等机制——这些在关机设备上完全不可用。

2. TCP 无法广播

TCP 是 点对点(单播)协议,不支持广播或多播。

魔术包必须以 广播形式 发送到整个局域网(或子网),才能被目标网卡捕获。

即使你知道 MAC 地址,TCP 也无法直接寻址到 MAC(它工作在更高层)。

3. 魔术包必须是 UDP + 广播 + 特定二进制格式

标准 WOL 魔术包要求:

使用 UDP 协议(无连接、可广播)。

目标端口通常为 7(Echo)或 9(Discard)(也可自定义,但需网卡支持)。

数据内容为:6 字节 0xFF + 16 次重复的目标 MAC 地址(共 102 字节)。

必须通过 二层广播(如 255.255.255.255 或子网广播地址)发送。


浏览65
返回
目录
返回
首页
Qt5.15.2 C++ 在一个 .h 头文件中定义多个类 Qt5 C++环境下多模块独立线程运行与通信