之前我的一篇文章《網絡喚醒全攻略(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;
}
更多細節請 閱讀原文