Qt5.15.2 C++ 使用 UDP 发送 Wake-on-LAN(WOL)魔术包唤醒远端计算机
#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;
}注意事项:
目标计算机必须支持并启用 Wake-on-LAN(通常在 BIOS/UEFI 和网卡驱动中设置)。
发送方和目标必须在同一局域网(除非路由器支持转发 WOL 包)。
防火墙不能阻止 UDP 端口 7/9 的广播。
MAC 地址格式必须为
XX:XX:XX:XX:XX:XX(不区分大小写,也可用-,但需修改解析逻辑)。在某些系统上,可能需要管理员权限才能发送广播包(尤其是 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 或子网广播地址)发送。
目录 返回
首页