每日一博 | java 通过网络唤醒实现远程开机

栏目: Java · 发布时间: 8年前

内容简介:每日一博 | java 通过网络唤醒实现远程开机

1. 在BIOS设置支持网络唤醒

大多数集成网卡都能实现 网络唤醒 功能,不过需要事先进入BIOS中开启网络唤醒功能,不同主板的设置不一样,以VIA 主板为例,在BIOS中找到“OnBoard LAN”选项,将它设成“Enabled”。同时将“POWER MANAGEMENT SETUP( 电源管理 设置)”下的“Power On by LAN/Ring”选项设为“Enabled”,最后将“Wake On LAN(网络唤醒)”选项设置为“Enabled”,设置好后保存退出。

不同系统可能还需要额外的操作才能保证网络唤醒的可用性,以win10系统为例:

打开设备管理器,进入网络适配器中自己网卡的属性设置,把相关的服务都启用了。

每日一博 | java 通过网络唤醒实现远程开机

2. 网络唤醒的必备条件

  • 网络唤醒需要终端的主板和网卡支持,需要先在BIOS设置支持网络唤醒
  • 网络唤醒要接通电源保证网卡能通电 要接网线 不能是wifi
  • 如果强制关机 可能不能通过网络唤醒来开机
  • 跨交换机或者跨路由的话就有可能不支持唤醒
  • 跨多层交换机的话即使ping通也未必能唤醒
  • 在同一网段下进行网络唤醒最为省事

3. 网络唤醒原理

这里提到一个魔术包 Magic Packet 的概念,魔术包指AMD公司开发的唤醒数据包,其实是一种特定的数据格式。将唤醒魔术包发送的被唤醒机器的网卡上,具有远程唤醒的网卡都支持这个标准,用16进制表示。

假设你的网卡物理地址为00:15:17:53:d4:f9, 这段Magic Packet内容如下:

FFFFFFFFFFFF00151753d4f900151753d4f900151753d4f900151753d4f9

00151753d4f900151753d4f900151753d4f900151753d4f900151753d4f9

00151753d4f900151753d4f900151753d4f900151753d4f900151753d4f9

00151753d4f900151753d4f9

这段数据转化为二进制的数据,通过socket技术发送数据包以及目的mac和目的广播地址,就会唤醒目的网卡,从而唤醒主机。

数据包流向图:

每日一博 | java 通过网络唤醒实现远程开机

当数据包被广播到192.168.1网段之后,根据数据携带的mac信息匹配到具体的主机。

4. 广播地址

这里主要讲解广播地址的概念和计算。

所谓 广播地址 指同时向网上所有的主机发送报文。

对一个既定的ip来说,其网络地址就是主机位全换成0, 广播地址 就是主机位是全换成1

例子:先把子网掩码化成二进制,再对应的把子网掩码后面是0的部分对着Ip地址换成0和1就是网络地址和 主机地址 ,比如

192.168.1.3 (地址)/255.255.255.252(掩码) ,换算一下成二进制

11111111.11111111.11111111.111111 00 /掩码

11000000.10101000.00000001.000000 11 /地址

掩码后两位是0,那么把地址的后两位换成0就是网络地址,换成1就是 广播地址

那么就是:11000000.10101000.00000001.000000 00

11000000.10101000.00000001.000000 11

把上面的 二进制转换 成10进制

得到192.168.1.0是网络地址,192.168.1.3是 广播地址

5. java代码-网络唤醒

先计算被唤醒主机的广播地址

//根据子网掩码和ip得到主机的广播地址
    public static String getBroadcastAddress(String ip, String subnetMask){
        String ipBinary = toBinary(ip);
        String subnetBinary = toBinary(subnetMask);
        String broadcastBinary = getBroadcastBinary(ipBinary, subnetBinary);
        String wholeBroadcastBinary=spiltBinary(broadcastBinary);
        return binaryToDecimal(wholeBroadcastBinary);
    }

    //二进制的ip字符串转十进制
    private static String binaryToDecimal(String wholeBroadcastBinary){
        String[] strings = wholeBroadcastBinary.split("\\.");
        StringBuilder sb = new StringBuilder(40);
        for (int j = 0; j < strings.length ; j++) {
            String s = Integer.valueOf(strings[j], 2).toString();
            sb.append(s).append(".");
        }
        return sb.toString().substring(0,sb.length()-1);
    }

    //按8位分割二进制字符串
    private static String spiltBinary(String broadcastBinary){
        StringBuilder stringBuilder = new StringBuilder(40);
        char[] chars = broadcastBinary.toCharArray();
        int count=0;
        for (int j = 0; j < chars.length; j++) {
            if (count==8){
                stringBuilder.append(".");
                count=0;
            }
            stringBuilder.append(chars[j]);
            count++;
        }
        return stringBuilder.toString();
    }

    //得到广播地址的二进制码
    private static String getBroadcastBinary(String ipBinary, String subnetBinary){
        int i = subnetBinary.lastIndexOf('1');
        String broadcastIPBinary = ipBinary.substring(0,i+1);
        for (int j = broadcastIPBinary.length(); j < 32 ; j++) {
            broadcastIPBinary=broadcastIPBinary+"1";
        }
        return broadcastIPBinary;
    }

    //转二进制
    private static String toBinary(String content){
        String binaryString="";
        String[] ipSplit = content.split("\\.");
        for ( String split : ipSplit ) {
            String s = Integer.toBinaryString(Integer.valueOf(split));
            int length = s.length();
            for (int i = length; i <8 ; i++) {
                s="0"+s;
            }
            binaryString = binaryString +s;
        }
        return binaryString;
    }

执行网络唤醒

/**
     * 唤醒主机
     * @param ip         主机ip
     * @param mac     主机mac
     * @param subnetMask      主机子网掩码
     */
    public static void wakeUpDevice(String ip,String mac,String subnetMask){
        ip=ip.trim();
        mac=mac.trim();
        subnetMask=subnetMask.trim();
        String broadcastAddress=getBroadcastAddress(ip,subnetMask);
        mac = mac.replace("-", "");
        wakeBy(broadcastAddress,mac,389);
    }

    /**
     *   网络唤醒
     * @param ip            主机ip
     * @param mac        主机mac
     * @param port        端口
     */
    private static void wakeBy(String ip, String mac, int port) {
        //构建magic魔术包
        String MagicPacage = "FFFFFFFFFFFF";
        for (int i = 0; i < 16; i++) {
            MagicPacage += mac;
        }
        byte[] MPBinary = hexStr2BinArr(MagicPacage);
        try {
            InetAddress address = InetAddress.getByName(ip);
            DatagramSocket socket = new DatagramSocket(port);
            DatagramPacket packet = new DatagramPacket(MPBinary, MPBinary.length, address, port);
            //发送udp数据包到广播地址
            socket.send(packet);
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static byte[] hexStr2BinArr(String hexString) {
        String hexStr = "0123456789ABCDEF";
        int len = hexString.length() / 2;
        byte[] bytes = new byte[len];
        byte high = 0;
        byte low = 0;
        for (int i = 0; i < len; i++) {
            high = (byte) ((hexStr.indexOf(hexString.charAt(2 * i))) << 4);
            low = (byte) hexStr.indexOf(hexString.charAt(2 * i + 1));
            bytes[i] = (byte) (high | low);
        }
        return bytes;
    }

注意:当跨网段进行唤醒时,即发起唤醒的地址和被唤醒的目的地址不在同一个网段,是否需要做一些调整取决于你的网络配置。我这边的情况是,比如当50网段的服务器发送网络唤醒魔术包到62网段,是行不通的,需要在62网关下增加ip转发广播ip forward-broadcast。


以上所述就是小编给大家介绍的《每日一博 | java 通过网络唤醒实现远程开机》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Code

Code

Charles Petzold / Microsoft Press / 2000-10-21 / USD 29.99

Paperback Edition What do flashlights, the British invasion, black cats, and seesaws have to do with computers? In CODE, they show us the ingenious ways we manipulate language and invent new means of ......一起来看看 《Code》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试