
之前我的一篇文章《网络唤醒全攻略(Wake On Lan)》介绍过如何设置远程唤醒电脑,着重于使用,这篇主要从原理方面解析一下当中的奥妙;
原理
将唤醒魔术包发送的被唤醒机器的网卡上,魔术包指AMD公司开发的唤醒数据包,具有远程唤醒的网卡都支持这个标准,用16进制表示如下:
6对“FF”前缀+16次重复MAC地址,举个例子假如我的网卡MAC地址是:AA:BB:CC:DD:EE:FF:11
那么魔术包就是:
0xFFFFFFFFFFAABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11AABBCCDDEEFF11
但是传送的时候必须封包成二进制格式才可以传送,简单来说,我们抽2个区段分析:
FFFFFFFFFFF 转成: 11111111 11111111 11111111 11111111 11111111 11111111
AABBCCDDEEFF11 转成:10101010 10111011 11001100 11011101 11101110 11111111 00010001
那么封包后就是把每个字节连接在一起:
11111111 11111111 11111111 11111111 11111111 11111111 10101010 10111011 11001100 11011101 11101110 11111111 00010001
……..10101010 10111011 11001100 11011101 11101110 11111111 00010001(第16次)
开发实现
关键代码(Java):
private String Wake(String name, String host, String mac, int port) {
try {
byte[] macBytes = getMacBytes(mac);//转成字节类型
byte[] bytes = new byte[6 + 16 * macBytes.length];
for (int i = 0; i < 6; i++) {
bytes[i] = (byte) 0xff;
}
for (int i = 6; i < bytes.length; i += macBytes.length) {
System.arraycopy(macBytes, 0, bytes, i, macBytes.length); //放入16个MAC地址
}
InetAddress address = InetAddress.getByName(host);
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
socket.close();
return "wol_package_sent_success";
} catch (Exception e) {
return "wol_package_sent_fail";
}
}
private static byte[] getMacBytes(String mac) throws IllegalArgumentException {
byte[] bytes = new byte[6];
String[] hex = mac.split("(\\:|\\-)");
if (hex.length != 6) {
throw new IllegalArgumentException("Invalid MAC address.");
}
try {
for (int i = 0; i < 6; i++) {
bytes[i] = (byte) Integer.parseInt(hex[i], 16);
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid hex digit in MAC address.");
}
return bytes;
}
更多细节请 阅读原文