远程开机原理

远程开机简称WOL(Woke on LAN),它是通过局域网实现远程开机。我们只需知道某一台处于局域网计算机的MAC地址,结合一定的软件,就能实现远程开机。它的工作过程是这样的:局域网中的计算机处于关机状态,但它的网卡处于监控状态,等待网络开机的数据包。一旦收到该数据包,网卡就能打开主机电源实现开机。要唤醒某一台电脑必须知道该电脑的编号,在没有开机的状态下我们不可能通过 IP或主机名来区分计算机,但每一块网卡都有惟一的MAC地址,通过教师机向该网卡发出“Wake up”的数据包,该机虽然处于关机状态,但网卡上的芯片可以通过三芯连接线获得电源,从而处理数据包中的地址信息确定是否开机,如果确认就通过三芯连接线向计算机发出开机信号。

硬件要求

远程开机的硬件要求 远程开机并不是每一台计算机都能实现的,它对网卡、主板、电源都有要求。

网卡

网卡是实现远程开机的一个最重要的元素,不是所有网卡都支持远程开机。一些报价在50元左右的网卡因为成本有限,往往不支持远程开机。目前比较流行的STAR-901、STAR-902、D-Link530TX、联想LN-1068A等都支持远程开机。购买网卡时我们可以向经销商咨询。一般来说,支持远程开机的网卡都有三针的WOL接口(请见图1),并赠送一根三芯连接线,以便和主板相连接,同时也要注意一下产品说明书。对于不支持该功能的网卡可以购买相适应的远程开机模块,效果是一样的。

主板

主板不支持远程开机也是不行的。支持该功能的主板上一般都在PCI插槽附近有一个三芯插座用三芯连接线把网卡和主板连接起来。

要实现远程开机必须给网卡电源,由于计算机处于关机状态,一般不能通过PCI插槽给网卡供电,所以必须通过三芯连接线给网卡电流。而有些最新的主板(PCI2.2标准)在关机状态下能够给PCI电源,所以这种主板就没有必要设三芯插座了。

设置CMOS的相关参数

当然,我们还需要设置一下CMOS的相关参数。开机按下Delete键进入CMOS设置界面,找到“Power Management Setup”电源管理菜单,回车进入子菜单,找到“Wake up Events”,回车后找到“Wake up on LAN/Ring”选项,将“Disabled”改为“Enabled”。保存退出CMOS设置。

python代码实现

from optparse import OptionParser
import socket
import struct

def wake(addr, mac):
    mac_data = []
    for i in range(0, 12, 2):
        mac_data.append(int(mac[i:i+2], 16))
    packet = struct.pack("!BBBBBB", 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
    packet_mac = struct.pack("!BBBBBB", *mac_data)
    for i in range(0, 16):
        packet += packet_mac
    #print "len: ", len(packet), "data: ", packet
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    try:
        s.sendto(packet, addr)
        print "唤醒数据包发送完成", addr, mac
    finally:
        s.close()

def main():
    usage = "%prog [options]"
    parser = OptionParser(usage = usage)
    parser.add_option("-a", "--addr", dest="addr", help="Boardcast address", metavar="255.255.255.255")
    parser.add_option("-p", "--port", dest="port", help="Port", metavar="7")
    parser.add_option("-m", "--mac", dest="mac", help="MAC address", metavar="FF-FF-FF-FF-FF-FF")
    (options, args) = parser.parse_args()
    if not options.mac:
        parser.print_help()
        return
    addr = "255.255.255.255"
    port = 7
    mac = options.mac.replace("-", "")
    if options.addr:
        addr = options.addr
    if len(mac) != 12:
        print "无效的MAC地址: %s" % options.mac
        return
    if options.port:
        port = int(options.port)
    wake((addr, port), mac)

if __name__ == "__main__":
    main()