java 远程开关机

一 远程开机(wake-on-lan)
wake on lan 技术通过发送特殊的网络数据包远程启动处于关机状态的计算机.
wake on lan 有多种实现方法,其中之一是由AMD和HP提出的Magic Packet方法。采用这种方法需要系统主板和网卡的支持,并且要在bios里将主板的wake on lan 启用.

Magic Packet可以是任何协议的数据帧(IP,UDP等),该数据帧中包含了下列内容

FF FF FF FF FF FF 11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66
11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66
11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66
11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66 11 22 33 44 55 66

即6字节FF,后跟16次该网卡的硬件地址.当支持远程唤醒的网卡接收到这样的数据包时,它就会作出反应,通知主机开机.
   下面把实现的主要代码贴出来,这些代码有些部分也是从网上搜索得到,经过修改完善够唤醒远程主机.(我将实现放到了一个servlet里)
  
WakeUpServlet.java

import java.io.IOException;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class WakeUpServlet extends HttpServlet {

/**
* Constructor of the object.
*/
public WakeUpServlet() {
super();
}

/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}


public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

wakeUpOnLan();
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

wakeUpOnLan();
}

public void init() throws ServletException {
// Put your code here
}





/**
* 将16进制的mac地址转换为二进制
* @param macStr
* @return
* @throws IllegalArgumentException
*/

    private static byte[] getMacBytes(String macStr) throws IllegalArgumentException {
        byte[] bytes = new byte[6];
        String[] hex = macStr.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;
    }
   

public boolean  wakeUpOnLan() throws IOException{
int port = 10000;
String macAddress = "00-10-C6-B7-6F-EE";
String destIP = "255.255.255.255";//广播地址

        //检测 mac 地址,并将其转换为二进制
byte[] destMac = getMacBytes(macAddress);
        if(destMac == null)
        return false;

        InetAddress destHost = null;
        try {
            destHost = InetAddress.getByName(destIP);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //construct packet data
        byte[] magicBytes = new byte[102];
       
        //将数据包的前6位放入0xFF即 "FF"的二进制
        for(int i = 0; i < 6; i++)
        magicBytes[i] = (byte)0xFF;
       
        //从第7个位置开始把mac地址放入16次
        for(int i = 0; i < 16; i++){
            for(int j = 0; j < destMac.length; j++){
            magicBytes[6+destMac.length*i+j] = destMac[j];
            } 
        }
        //create packet
        DatagramPacket dp = null;
        dp = new DatagramPacket(magicBytes,magicBytes.length,destHost,port);
        DatagramSocket ds = new DatagramSocket();
        ds.send(dp);
        ds.close();
return true;
   
}

/*一下为将16进制字符串转换为二进制的又一个方法,此实现中没有用到.它的作用和上面
private static byte[] getMacBytes(String macStr)是一样的.
*/
/**
* 将16进制字符串转换为二进制
* @param hex
* @return
*/
public static byte[] hexStringToByte(String hex) {
    int len = (hex.length() / 2);
    byte[] result = new byte[len];
    char[] achar = hex.toCharArray();
    for (int i = 0; i < len; i++) {
     int pos = i * 2;
     result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
    }
    return result;
}

private static byte toByte(char c) {
    byte b = (byte) "0123456789ABCDEF".indexOf(c);
    return b;
}

}

  下面是通过ip获取网卡mac地址的代码
private static String getMacAddressIP(String remotePcIP) {
String str = "";
String macAddress = "";
try {

Process pp = Runtime.getRuntime().exec("nbtstat -A " + remotePcIP);
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
for (int i = 1; i < 100; i++) {
str = input.readLine();

if (str != null) {
if (str.indexOf("MAC Address") > 1) {
macAddress = str.substring(
str.indexOf("MAC Address") + 14, str.length());
break;
}
}
}
} catch (IOException ex) {

}
return macAddress;
}


二 远程关机
   远程关机是通过"shutdown"命令实现的.
  C:\Documents and Settings\Administrator>shutdown /s /m \\computerIp
  代码就不详细说明了,主要是说一下注意事项.
  要实现远程关机,被关的主机要在组策略里做一些设置.
   1、单击“开始”按钮,选择“运行”,在对话框中输入“gpedit.msc”,然后单击“确定”,打开“组策略编辑器”。

  2、在“组策略”窗口的左窗格中打开“计算机配置”—“Windows 设置”—“安全设置”—“本地策略”—“用户权利指派”。

  3、在“组策略”窗口的右窗格中选择“Force shutdown from a remote system (从远端系统强制关机)”,双击。

  4、在弹出的对话框中显示目前只有“Administrators”组的成员才有权从远程关机;单击对话框下方的“添加用户或组”按钮,然后在新弹出的对话框中输入“guest”,再单击“确定”。

  5、这时在“从远端系统强制关机”的属性中便添加了一个“guest”用户,单击“确定”即可。

   windows2003,xp远程关机的差异:
   进行了上面的设置后,xp作为主机,关闭其他操作系统时没有问题.如果时windows2003作为主机,关闭其他机器时,总是提示"拒绝访问".这是由于操作系统的原因,因此,2003关闭其他机器时,要先执行
C:\Documents and Settings\Administrator>net use \\computerIP\IPC$ "password" /user:"administrator"

  
  

你可能感兴趣的:(java,.net,servlet,XP,HP)