远程开机关机_第1页
远程开机关机_第2页
远程开机关机_第3页
远程开机关机_第4页
远程开机关机_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、远程开机关机作为机房管理员,要管理的计算机较多,经常面临大量计算机要开启或关闭,如果每次逐一去开启或关闭,也是一项艰巨的任务,如果能从一台计算机上远程开启或关闭本局域网内的一台或多台计算机,将是一件轻松快乐的事。一、远程开机1对被开启计算机的硬件要求 要实现网络远程开机,对被开启的计算机而言需要电源、主板、网卡3件设备的支持。首先电源必须是符合atx 2.03标准的atx电源,而且其+5v的备用电流必须在600ma以上,以便能唤醒网卡。其次是主板和网卡都必须支持wake-up on lan(wol)技术(即远程唤醒)。可通过查看主板网卡使用说明书确认,对主板而言可直接查看bios设置中的“po

2、wer management setup”菜单中是否有“wake on lan”一项来确认,有则将“wake on lan”设置为“enable”, 开启远程唤醒功能。另外查看bios设置中是否有“wake on pci card”,有则说明主板可通过pci插槽直接向网卡供电,将其设置为“enable”;没有则需要在主板的wol接口(3针)和网卡的wol接口之间连一根三芯远程唤醒电缆,以便主板给网卡供电。 2远程开机原理远程开机的实现,主要是向目标计算机发送特殊格式的数据包(包含有6个字节的“ff”和重复16遍的目标计算机的mac地址,共102个字节的数据),目标计算机的网卡只要检测到数据包中

3、某个片段含有这102个字节的数据,便会将该计算机唤醒,它是amd公司开发推广的技术。所以远程开机需要知道目标计算机的mac地址,如果要开启的计算机只有一台,可直接在该计算机上查看mac地址并记录下来,但是如果有多台计算机需要开启,用这种方式麻烦且容易出错,所以应考虑编程解决这个问题。3编程获取局域网内各计算机的mac地址怎么获取局域网内各计算机的mac地址呢?了解网络通信原理的人都知道,网络中两台计算机要相互通信,看似只要相互知道ip地址即可,但那只是在网络层上,在数据链路层上最终必须知道对方计算机网卡的物理地址,即mac地址。那么网络通信时如何知道其它计算机的mac地址呢?靠arp(addr

4、ess resolution protocol)即地址解析协议,通过在局域网内广播arp请求包,对方即会响应,告知其mac地址,双方计算机都会将对方的mac地址及ip地址对应保存在一张地址映射表中,以备通信使用。所以编程时要发送一个arp请求包来获取指定计算机的mac地址,windows api中已提供现成的函数sendarp,其声明如下:dwordsendarp(ipaddr destip, ipaddr srcip,pulong pmacaddr, pulong phyaddrlen );第一个参数为要获取其mac地址的目标计算机机的ip地址,参数类型为ipaddr ,其实类型就是unsi

5、gned long (用户输入的目的主机的ip地址一般是字符串类型点式ip地址,需要将其转换成一个3 2位的无符号长整数,可用inet_addr函数完成);第二个参数为源机的ip地址;第三个参数为存放目标计算机mac地址的指针变量;第四个参数为存放目标计算机mac地址字节长度的指针变量。该函数的定义在iphlpapi.h头文件中,所以要包含#include;该函数的实现在iphlpapi.lib库文件中,要在项目设置的链接中加入库文件iphlpapi.lib。(注意:vc6.0不含这两个文件,需网上下载,而vc7.0中含有。)关键代码如下:/将用户输入的目的主机的字符串类型点式ip地址转换成一

6、个3 2位的无符号长整数:ulong uldestip=inet_addr(stripaddr);/发送arp请求包获得远程mac地址:irusult=sendarp(uldestip,(unsigned long)null,(pulong)&ulmacadd,&phyaddrlen); /由于获得的mac地址是6字节的unsigned char数值,不便阅读,所以需要将其转换为字符串:sprintf(strmacaddr,%.2x-%.2x-%.2x-%.2x-%.2x-%.2x,ulmacadd0,ulmacadd1,ulmacadd2,ulmacadd3,ulmacadd4,ulmaca

7、dd5);为了实现获取机房内所有机器的mac地址,可以采取循环的办法发送arp请求包获得所有机器的mac地址,考虑机房内机器的ip地址一般都是连续的,所以先获取ip地址最小的那台机器的mac地址,然后逐一增加ip地址, 循环获取其它机器的ip地址。/注意ip地址加一前先要将ulong类型的ip地址从网络字节顺序转换为主机字节顺序,加一后再从主机字节顺序转换为网络字节顺序。uldestip=htonl(ntohl(uldestip)+1); 为了使用户能对比观察及关机的需要,程序中还获取了远程机的机器名,并与ip地址、mac地址一起显示在一个listctrl控件中。/获取远程机器名:struct

8、 hostent *remotehost; remotehost=(struct hostent*)malloc(sizeof(struct hostent);remotehost=gethostbyaddr(char*)&uldestip,4,af_inet); strcpy(strremotehostname,remotehost-h_name); /将3 2位的无符号长整数ip地址转换成字符串类型点式ip地址:struct in_addr saddr; saddr.s_addr=uldestip; strcpy(stripaddr,inet_ntoa(saddr);/将远程机的机器名、i

9、p地址、mac地址一起显示在一个listctrl控件中:int iitemnumber=m_listhostinfo.getitemcount();char strnumber4;sprintf(strnumber,%d,iitemnumber+1);m_listhostinfo.insertitem(iitemnumber,strnumber); /第一列显示序号m_listhostinfo.setitemtext(iitemnumber,1,strremotehostname); /第二列显示机器名m_listhostinfo.setitemtext(iitemnumber,2,strip

10、addr); /第三列显示ip地址m_listhostinfo.setitemtext(iitemnumber,3,strmacaddr); /第四列显示mac地址为了下次开机的需要,要将listctrl控件中显示的机器名、ip地址、mac地址一一对应保存在一个文件中。远程开机前,需要将文件中的机器名、ip地址、mac地址读出来显示在listctrl控件中,在程序启动后(比如在oninitdialog函数中)就读出来显示,以便开机和关机都可以使用。文件读写的代码比较简单,这里就不再赘述。4.发送远程开机数据包已经知道了要开启计算机的mac地址,接下来便可发送远程开机的数据包了,采用广播形式发送

11、。关键代码如下:socket socketdata=socket(af_inet, sock_dgram, 0); /创建套接字bool boptval=true;int irusult=setsockopt(socketdata,sol_socket,so_broadcast,(char far *)&boptval,sizeof(boptval);/设置发送方式为广播发送sockaddr_in recvaddr;recvaddr.sin_family = af_inet; recvaddr.sin_port = htons(0);recvaddr.sin_addr.s_addr=htonl

12、(inaddr_broadcast);为了将listctrl控件中所选择的计算机都开启,需要获取所有选择项中的mac地址,然后构造远程开机数据包,逐机发送。关键代码如下:position pos=m_listhostinfo.getfirstselecteditemposition(); while(pos) int nitem=m_addrlistctrl.getnextselecteditem(pos);/获取选择项 strmacaddr=m_listhostinfo.getitemtext(nitem,3);/获取选择项的第四列数据mac地址byte bytemacaddr6; /将字符

13、串型式mac地址转换为6个字节的数值:sscanf(strmacaddr, %2x-%2x-%2x-%2x-%2x-%2x,&bytemacaddr0, &bytemacaddr1, &bytemacaddr2, &bytemacaddr3, &bytemacaddr4, &bytemacaddr5);/构造远程开机数据包byte bdatapacket102;memset(bdatapacket,0xff,6);/先写入6个字节的fffor (int i=1; igetmainwnd();while(1)sockaccept=accept(powerdlg-m_socklisten,(soc

14、kaddr*)&clientaddr,&iaddrlen);ulclientipaddr=clientaddr.sin_addr.s_addr;for(int i=0;im_listhostinfo.getitemcount();i+)stripaddr=powerdlg-m_listhostinfo.getitemtext(i,2);if(ulclientipaddr=inet_addr(stripaddr)powerdlg-m_sockclienti=sockaccept;/为了知道哪些客户机已建立了连接,我顺便在listctrll控件中对应连接客户机那一行的第五列打作为标记:powerd

15、lg-m_listhostinfo.setitemtext(i,4,);break;最后在用户点击关机按钮或菜单时发送自定义的关机命令字符串:position pos=m_listhostinfo.getfirstselecteditemposition(); while(pos) int nitem=m_listhostinfo.getnextselecteditem(pos);/获取选择项 send(m_sockclientnitem,powoff,com_str_len,0);closesocket(m_sockclientnitem);/关闭套接字m_listhostinfo.seti

16、temtext(nitem,4,); (2)客户端先解析服务器名,然后用s o c k e t创建一个套接字,再用c o n n e c t创建与服务器的连接。最后等待接收关机命令字符串:cstring strserveripaddr=;/此处为服务端的ip地址socket sockclient;sockaddr_in serversockaddr;serversockaddr.sin_addr.s_addr=inet_addr(strserveripaddr);serversockaddr.sin_family=af_inet;serversockaddr.sin_po

17、rt=htons(server_port);sockclient=socket(af_inet,sock_stream,0);while(connect(sockclient,(sockaddr*)&serversockaddr,sizeof(serversockaddr)!=0);int iallrecvlen=0,ithisrecvlen=0;char strrecvbufcom_str_len+1=;while(ithisrecvlen!=socket_error&iallrecvlencom_str_len)/循环接收数据ithisrecvlen=recv(sockclient,str

18、recvbuf+iallrecvlen,com_str_len,0);iallrecvlen+=ithisrecvlen;被控端收到命令字符串后,调用exitwindowsex函数关闭或重启本客户机。exitwindowsex函数在windows9x系统中可直接使用,在windows2000或windows以上系统中默认的情况下进程不具有关机权限,所以要将当前进程的关机权限enabled。先通过openprocesstoken函数获得当前进程访问令牌的句柄,该函数声明如下:boolopenprocesstoken (handle processhandle,dword desiredacces

19、s,phandle tokenhandle);第一参数是要修改权限的进程句柄;第二个参数为对该令牌的访问类型;第三个参数即获得的进程访问令牌的句柄。为了修改进程令牌权限,还要先定义一个令牌权限token_privileges类型结构变量,该结构定义如下:typedef struct _token_privileges dword privilegecount; luid_and_attributes privilegesanysize_array; token_privileges第一个成员变量为权限数量;第二个成员变量为luid_and_attributes类型结构变量数组。该结构定义如下:

20、typedef struct _luid_and_attributes luid luid; dword attributes; luid_and_attributes;第一个成员变量为某权限的本地唯一标识;第二个成员变量为该权限属性。为了获取某权限的本地唯一标识,需要通过lookupprivilegevalue函数,该函数声明如下:boollookupprivilegevaluea(lpcstr lpsystemname,lpcstr lpname,pluid lpluid);第一个参数为系统名,本地系统为nul;第二个参数为权限名;第三个参数为返回的权限本地唯一标识。定义好了令牌权限tok

21、en_privileges结构变量后,最后通过adjusttokenprivileges函数修改访问令牌权限,该函数声明如下:booladjusttokenprivileges (handle tokenhandle,bool disableallprivileges, ptoken_privileges newstate,dword bufferlength,ptoken_privilegesreviousstate, pdword returnlength);第一个参数为访问令牌句柄;第二个参数为是否取消所有权限;第三个参数为前面定义好的令牌权限;后面三个参数针用于保存修改前的令牌权限,分

22、别为用于保存的内存长度、保存的内存地址、实际保存的内存长度。具体代码如下:if(strcmp(powoff,strrecvbuf)=0)closesocket(sockclient);wsacleanup();if(getversion()0x80000000)/判断windows系统版本号handle hprocesstoken;token_privileges tkp;openprocesstoken(getcurrentprocess(),token_adjust_privileges|token_query,&hprocesstoken);lookupprivilegevalue(nu

23、ll,se_shutdown_name,&tkp.privileges0.luid);tkp.privilegecount = 1; tkp.privileges0.attributes = se_privilege_enabled;adjusttokenprivileges(hprocesstoken,false,&tkp,0,(ptoken_privileges)null,0);/强迫所有进程退出、关闭计算机并切断电源exitwindowsex(ewx_force|ewx_poweroff,0); 在windows2000或windows以上系统中,也可用initiatesystemshu

24、tdown函数代替exitwindowsex函数关闭本机,initiatesystemshutdown函数的使用在下面介绍。2无被控端软件由于windows2000、windowsxp以上的系统本身支持远程关机,所以也可不编写被控端软件,windows api中已提供现成的函数initiatesystemshutdown,其声明如下:boolinitiatesystemshutdowna(lpstr lpmachinename,lpstr lpmessage,dword dwtimeout,bool bforceappsclosed,bool brebootaftershutdown);第一个

25、参数为机器名,本机为null;第二个参数为关机提示对话框中显示的消息;第三个参数为关机前提示的时间;第四个参数为是否强制关闭应用程序;第五个参数为是否重启。远程关机需要具有相应权限,如果在域环境下可以直接以域管理员身份登录系统获得远程关机的权限,一般在机房或网吧中都是工作组环境,无法直接获得远程关机的权限,怎么办呢?通过试验我找到了一个办法,具体步骤如下:(1)在被控机上通过“计算机管理”建立一个用户,然后在“组策略”中给该用户配置远程关机权限,具体操作为:运行“gpedit.msc”打开“组策略编辑器”。在“组策略”左侧树窗口中依次打开“计算机配置”、“windows 设置”、“安全设置”、

26、“本地策略”、“用户权利指派”。在“组策略”右侧列表窗口选择“从远端系统强制关机”策略添加该用户。(2)在工作组环境中无法直接以该用户账号从控制机登录被控机,需要在控制机上创建与被控机上一致的用户账号(用户名和密码都需相同),可预先通过“计算机管理”完成,也可在调用关机代码前临时通过下面的代码来创建:net_api_status retstatus = 0;dword dwerror = 0; user_info_1 structuserinfo;zeromemory(&structuserinfo, sizeof(structuserinfo);structuserinfo.usri1_name = szusername;structuserinfo.usri1_password= szpassword;structuserinfo.usri1_priv = user_priv_user;structuserinfo.usri1_flags = uf_normal_account;retstatus = netuseradd(null, 1, (lpbyte)(&structuserinfo), &d

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论