首先介绍相关知识。
UDP协议
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。
下面是UDP与TCP的一些区别:
**A)**UDP是无连接的。相比于TCP协议,UDP协议在传送数据前不需要建立连接,当然也就没有释放连接。
**B)**UDP是尽最大努力交付的。也就是说UDP协议无法保证数据能够准确的交付到目的主机。也不需要对接收到的UDP报文进行确认。
**C)**UDP是面向报文的。也就是说UDP协议将应用层传输下来的数据封装在一个UDP包中,不进行拆分或合并。因此,运输层在收到对方的UDP包后,会去掉首部后,将数据原封不动的交给应用进程。
**D)**UDP没有拥塞控制。因此UDP协议的发送速率不送网络的拥塞度影响。
**E)**UDP支持一对一、一对多、多对一和多对多的交互通信。
**F)**UDP的头部占用较小,只占用8个字节。
阻塞与非阻塞
简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,否则就可以理解为非阻塞。
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
举个栗子:
你问书店老板有没有《深入浅出MFC》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果;如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
IPAddress类
提供网际协议地址
IPAddress.Broadcast 字段
提供IP广播地址,此字段为只读。
语法:public static readonly IPAddress Broadcast
Broadcast字段等效于以点分隔的四部分表示法格式的255.255.255.255
UdpClient类
提供用户数据报(UDP)网络服务
语法:public class UdpClient : IDisposable
UdpClient类提供了一些简单的方法,用于在阻止模式下发送和接受无连接UDP数据报。
您可以选择使用下面两种方法之一来建立默认远程主机:
1.使用远程主机名和端口号作为参数创建 UdpClient 类的实例。
2.创建 UdpClient 类的实例,然后调用 Connect 方法。
UdpClient.Connect 方法 (IPAddress, Int32)
使用指定的 IP 地址和端口号建立默认远程主机。
命名空间: System.Net.Sockets
程序集: System(在 System.dll 中)
语法:public void Connect(IPAddress addr, int port)
参数:
addr 要将数据发送到的远程主机的IPAddress
port 要将数据发送到的端口号。
如果在调用 Send 方法时指定了 IPAddress.Broadcast ,则可以将数据广播到默认的广播地址:255.255.255.255。
UdpClient.Send方法(Byte[], Int32)
将UDP数据报发送到远程主机。
语法:public int Send(byte[] dgram, int bytes)
参数:
dgram Byte类型的数组,它指定您打算以字节数据形式发送的UDP数据报
bytes 数据报中的字节数
返回值:已发送的字节数。
调用此方法将数据报发送在Connect方法中建立的远程主机,并返回发送的字节数。如果在调用此重载之前未调用Connect,则Send方法引发异常(SockeException)。
MAC地址
MAC(Media Access Control或者Medium Access Control)地址,意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。在OSI模型中,第三层网络层负责 IP地址,第二层数据链路层则负责 MAC地址。因此一个主机会有一个MAC地址,而每个网络位置会有一个专属于它的IP地址。 MAC地址是网卡决定的,是固定的。
谈起MAC地址,不得不说一下IP地址。IP地址工作在OSI参考模型的第三层网络层。两者之间分工明确,默契合作,完成通信过程。IP地址专注于网络层,将数据包从一个网络转发到另外一个网络;而MAC地址专注于数据链路层,将一个数据帧从一个节点传送到相同链路的另一个节点。
获取本机MAC地址
运行cmd,键入命令 ipconfig/all
远程唤醒
远程开机Wake onLAN(WOL),俗称远程唤醒,是现在很多网卡都支持的功能。而远程唤醒的实现,主要是向目标主机发送特殊格式的数据包,是AMD公司制作的MagicPacket这套软件以生成网络唤醒所需要的特殊数据包,俗称魔术包(Magic Packet)。MagicPacket格式虽然只是AMD公司开发推广的技术,并非世界公认的标准,但是仍然受到很多网卡制造商的支持,因此许多具有网络唤醒功能的网卡都能与之兼容。
原理上我们不用深入,实现上是发一个BroadCast包,包的内容包括以下数据就可以了。FF FF FF FF FF FF,6个FF是数据的开始,紧跟着16次MAC地址就可以了。
有了以上的基础知识,就要开始我们的项目了。用计算机(pc-A)唤醒局域网中的计算机(pc-B)。
设置pc-B
首先需要进行BIOS和网卡设置,启动计算机,进入BIOS参数设置。选择电源管理设置“Power Management Setup”选项,将“Wake up on LAN”项和“Wake on PCI Card”项均设置为“Enable”,启用该计算机的远程唤醒功能。
获取pc-B的Mac地址
通过命令行输入ipconfig/all可以得到pc-B的地址 00 0B 2F 70 40 9E
编码实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.Net;
namespace 远程唤醒开机
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static void WakeUp(byte[] mac)
{
UdpClient client = new UdpClient();
client.Connect(IPAddress.Broadcast, 9090);
//MessageBox.Show(IPAddress.Broadcast.ToString());
byte[] packet = new byte[17 * 6];
for (int i = 0; i < 6; i++)
packet[i] = 0xFF;
for (int i = 1; i <= 16; i++)
for (int j = 0; j < 6; j++)
packet[i * 6 + j] = mac[j];
int result = client.Send(packet, packet.Length);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
byte[] mac = new byte[6];
mac[0] = 0x00;
mac[1] = 0x0B;
mac[2] = 0x2F;
mac[3] = 0x70;
mac[4] = 0x40;
mac[5] = 0x9E;
WakeUp(mac);
}
}
}