数字家庭 (一) 开机

时间:2020-12-14 23:57:55

数码产品种类越来越多,让人目不暇接。当多种数码产品以及电脑、网络等放到一起的时候,就是我们充分发挥想象力,创造各种奇特的应用的时候了。

就拿这开机说起吧。当只有一台电脑的时候,开机是件再普通不过的事情了,轻轻按一下电源,开机就实现了。而当有两台电脑时,一台电脑已经打开了,现在我要打开另一台,是不是一定要站起来,走过去,按下电源呢?答案就不一定了。这里我要举两个例子,一是用一台电脑为另一台电脑开机,二是用手机让电脑开机。

如果要实现电脑的远程开机,一是要电脑的电源支持,二是要主板支持,三是要网卡支持,四是要控制远程开机的电脑与被控制的电脑在同一局域网内。幸运的是,现在大多数电源与集成网卡的主板是满足前三个条件的,只不过可能需要再BIOS里做些设置,例如要允许网卡BIOS、允许Wake up on LAN等。而第四个条件,对于数字家庭来说就更满足了。一个典型的scenario是:一个家庭有一台台式机和一台笔记本电脑,台式机通过网线连到无线路由器上,而笔记本则通过无线网上网。这家主人抱着笔记本来到厕所大号,突然想访问台式机上的一个文件,这时就可以通过运行一个远程开机软件来远程打开台式机,然后访问里面的资源。这种远程开机软件原理非常简单,完全可以自己写的,例如下面就是一段完整的实现远程开机的代码:(VC6编译)

 

  1.        WSADATA data;
  2.        WSAStartup(MAKEWORD(2, 0), &data);   //初始化socket环境
  3.        SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);    //创建一个UDP SOCKET
  4.        bool val = 1;
  5.        setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val));//设置广播模式
  6.        unsigned char mac[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; //假设你的台式机网卡的MAC地址是00-11-22-33-44-55
  7.        char buf[102];       //准备数据包,远程开机其实就是发送一个102字节长的UDP广播包
  8.        memset(buf, 0xff, 6);    //前六个字节固定都是0xff
  9.        for(int i = 0; i < 16; i++)       //之后把MAC地址重复16遍
  10.               memcpy(&buf[i * 6 + 6], mac, 6);
  11.        sockaddr_in to;
  12.        to.sin_family = AF_INET;
  13.        to.sin_port = 0;//端口无所谓的
  14.        to.sin_addr.s_addr = htonl(INADDR_BROADCAST); //发送数据到广播地址
  15.        sendto(sock, buf, 102, 0, (sockaddr*)&to, sizeof(to));       //发送。到这步时台式机就启动了
  16.        closesocket(sock);//关闭SOCKET

稍有点C++Winsock编程的基础的人应该很容易看懂这段代码,注意编译之前要include <winsock.h>,并且加上对ws2_32.lib的引用。把这段代码编译成一个基于控制台的EXE文件,拷到WINDOWS目录下,之后想开机时就可以直接按WIN+R,输入你的EXE的名字,就可以开机了。

另一种情况是你的笔记本电脑没有打开,但你拥有一台支持Wi-Fi的手机,那么你一样可以通过手机来远程打开电脑。这里以可以运行.Net程序的Windows Mobile环境为例,把上面的C++代码直接翻译成C#代码:

  1.               static void Main()
  2.               {
  3.                      Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  4.               //     s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, new byte[] { 1});
  5.                      byte[] data = new byte[102];
  6.                      for(int i = 0; i < 6; i++)
  7.                             data[i] = 0xff;
  8.                      for(int i = 0; i < 16; i++)
  9.                      {
  10.                             data[i * 6 + 6] = 0x00;
  11.                             data[i * 6 + 7] = 0x11;
  12.                             data[i * 6 + 8] = 0x22;
  13.                             data[i * 6 + 9] = 0x33;
  14.                             data[i * 6 + 10] = 0x44;
  15.                             data[i * 6 + 11] = 0x55;
  16.                      }
  17.                      System.Net.IPEndPoint addr = new System.Net.IPEndPoint(                          new System.Net.IPAddress(0xFFFFFFFF), 0);
  18.                      s.SendTo(data, addr);
  19.                      s.Close();
  20.               }

容易发现这段代码的原理与之前的大致相同,唯一不同的就是被注释掉的一行,它本来是用来设计Socket的广播模式的,在PC上运行时这一行是必须的,否则在调用SendTo方法时被有异常,但在手机上运行时这一行是不能要的,原因是SocketOptionName.Broadcast这个选项不受.NET Compact Framework支持,而不设置这个选项在手机一样可以发出广播包。

把这段C#代码编译成EXE文件,放到Windows Mobile环境下运行一下,果然成功。由此,我们进行了数字家庭的大门,为以后坐在沙发上什么都能干做出了迈出了第一步。