网络唤醒实现


网络唤醒

柠柠送了我一个树莓派,初步打算先拿来做连接局域网设备的跳板机(基于frp实现),顺便给台式机进行网络唤醒,以便出门时也能随时使用。

原理非常简单,在局域网内广播Magic Packet即可,Magic Packet的格式很简单,FFFFFFFFFFFF后重复目标主机的MAC地址即可。百度百科的网络唤醒词条有介绍:

网络唤醒_百度百科 (baidu.com)

初步打算利用Java实现,核心部分代码如下:

StringBuilder sb = new StringBuilder();
sb.append("FFFFFFFFFFFF");
for (int i = 0; i < 16; i++) {
    sb.append(mac);
}
String raw = sb.toString();

byte[] bytes = new byte[102];
for (int i = 0; i < 204; i += 2) {
    String temp = raw.substring(i, i + 2);
    bytes[i / 2] = (byte) Integer.parseInt(temp, 16);
}

最后将bytes广播即可。

最后,记着打开网卡网络唤醒的开关:开启网络唤醒支持

测试

代码打包成jar包,扔到树莓派上运行,电脑用WireShark抓包测试。

树莓派执行:

树莓派脚本执行“java -jar WOL.jar”

抓包结果:

WireShark抓包结果

成功抓到包,格式无误,测试完成。

完整代码:

package xyz.cambria.wol;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.*;
import java.util.Properties;

/**
 * @Author Cambria
 * @creat 2021/1/25 22:34
 */
public class WakeOnLan {
    public static void main(String[] args) {

        Properties properties = new Properties();

        try {
            properties.load(new FileInputStream("WOL.properties"));
        } catch (Exception e) {
            System.out.println("无法读取配置文件\"mac.properties\"");
            return;
        }

        String mac = properties.getProperty("mac");
        String address = properties.getProperty("address");
        if (mac == null || mac == "" || address == null || address == ""){
            System.out.println("配置文件格式错误,应为:\n\tmac = #{mac}\n\taddress = #{address}");
            return;
        }

        StringBuilder sb = new StringBuilder();
        sb.append("FFFFFFFFFFFF");
        for (int i = 0; i < 16; i++) {
            sb.append(mac);
        }
        String raw = sb.toString();

        byte[] bytes = new byte[102];
        for (int i = 0; i < 204; i += 2) {
            String temp = raw.substring(i, i + 2);
            bytes[i / 2] = (byte) Integer.parseInt(temp, 16);
        }

        DatagramPacket packet = null;
        try {
            packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName(address), 2333);
        } catch (UnknownHostException e) {
            System.out.println("IP地址格式错误");
            return;
        }

        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket();
        } catch (SocketException e) {
            System.out.println("创建socket出错");
            return;
        }

        try {
            socket.send(packet);
        } catch (IOException e) {
            System.out.println("IO错误,无法发送数据");
            return;
        }

        socket.close();

        System.out.println("唤醒包已发送");

        return;
    }
}

没错,这玩意早就在用了,不过一直是放到NAS上跑有些不伦不类。现在拿出来重新扔到树莓派上


文章作者: Cambria
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Cambria !
评论
  目录