Как стать автором
Обновить

Удаленное включение по Mac-адресу C# (Wake On Lan)

Время на прочтение12 мин
Количество просмотров38K
В этой статье я хотел бы поделиться небольшим опытом удаленного включения компьютера. Эта тема, пожалуй, многим известна, но хотелось бы еще раз уделить внимание данной технологии. Свою статью я разделю на две части:
  • Сканирование локальной сети, получение IP-адреса, HostName, Mac-address;
  • Создание "magic packet" и отправка.

Вот так примерно выглядит созданная программа:



Итак, приступим к выполнению первого пункта.

1. Сканирование локальной сети: получение IP-адреса, HostName, Mac-address


В настоящее время существует множество программ, которые реализуют данный пункт. В этой статье я напишу пример кода, который будет выполнять поставленную задачу.

Создадим новый проект в Visual Studio WPF C#. Для начала создадим основной элемент- это ListView, где будет выводится полученная информация.

Код XAML
 <ListView Margin="12,84,12,12" Name="listView1">
            <ListView.ContextMenu>
                <ContextMenu >
                    <MenuItem Header="Копировать">
                        <MenuItem Header="IP-adress" Name="copyIP" Click="copyIP_Click" />
                        <MenuItem Header="HostName" Name="copyName" Click="copyName_Click" />
                        <MenuItem Header="Mac-adress" Name="copyMacAddress" Click="copyMacAddress_Click" />
                    </MenuItem>
                    <MenuItem Header="Очистить список" Name="ClearList" Click="ClearList_Click" />
                    <MenuItem Header="Сохранить список"/>
                    <MenuItem Header="Действия">
                        <MenuItem Header="Удаленное включение" Name="PowerOn" Click="PowerOn_Click" />
                        <MenuItem Header="Удаленное завершение" IsEnabled="False" />
                    </MenuItem>
                    <MenuItem Header="Отмена"/>
                </ContextMenu>
            </ListView.ContextMenu>
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="IP-Адрес" DisplayMemberBinding="{Binding Path=ipAdress}" Width="200"></GridViewColumn>
                        <GridViewColumn Header="HostName" DisplayMemberBinding="{Binding Path=nameComputer}" Width="250"></GridViewColumn>
                        <GridViewColumn Header="Mac адрес" DisplayMemberBinding="{Binding Path=MacAdress}" Width="250"></GridViewColumn>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>

Код C#
 class TableHost
    {
        public string ipAdress { get; set; }
        public string nameComputer { get; set; }
        public string MacAdress { get; set; }
    }

Следующим действием узнаем свой IP-адрес и приступим к сканировании локальной сети. Код простой, даже для новичка он не вызовет особых трудностей.

Код C#

 // Получение ip-адреса.
            System.Net.IPAddress ip = System.Net.Dns.GetHostByName(host).AddressList[0];

 private void button2_Click(object sender, RoutedEventArgs e)
        {
            int i = int.Parse(ipToString[0]);
            int j = int.Parse(ipToString[1]);
                {
                    for(int k = 0;k<6;k++)
                    {
                        for (int m = 0; m < 254; m++)
                        {
                             //Запускаем проверку в новом потоке
                            Thread _thread = new Thread(() => GetInform(string.Format("{0}.{1}.{2}.{3}", i.ToString(), j.ToString(), k.ToString(), m.ToString())));
                            _thread.Start();                            
                        }
                    }
                }
               
        }
 private void GetInform(string textName)
        {
            string IP_Address = "";
            string HostName = "";
            string MacAddress = "";

            try
            {
                //Проверяем существует ли IP
                entry = Dns.GetHostEntry(textName);
                foreach (IPAddress a in entry.AddressList)
                {
                    IP_Address = a.ToString();
                    break;
                }

                //Получаем HostName
                HostName = entry.HostName;

                //Получаем Mac-address
                IPAddress dst = IPAddress.Parse(textName); 

                byte[] macAddr = new byte[6];
                uint macAddrLen = (uint)macAddr.Length;

                if (SendARP(BitConverter.ToInt32(dst.GetAddressBytes(), 0), 0, macAddr, ref macAddrLen) != 0)
                    throw new InvalidOperationException("SendARP failed.");

                string[] str = new string[(int)macAddrLen];
                for (int i = 0; i < macAddrLen; i++)
                    str[i] = macAddr[i].ToString("x2");

                MacAddress = string.Join(":", str);

                //Далее, если всё успешно, добавляем все данные в список, после чего выводим всё в ListView
                Dispatcher.Invoke(new Action(() =>
                {

                    _host.Add(new TableHost() { ipAdress = IP_Address, nameComputer = HostName, MacAdress = MacAddress });
                    listView1.ItemsSource = null;
                    listView1.ItemsSource = _host;
                }));
            }
            catch { }
           
        }

Теперь мы имеем всё, что нам необходимо. Приступаем к следующему этапу.

2. Создание «magic packet» и отправка


С определением вы можете ознакомится здесь. Этот этап, как вы сами понимаете, будет работать только с выключенным компьютером, так что нам необходимо будет сохранить всю информацию. Полный код я напишу в конце статьи.

Код на самом деле не такой то уж и страшный, деятельность этого пункта можно разделить на два этапа: создание пакета и его отправка.

Код C#

        [DllImport("iphlpapi.dll", ExactSpelling = true)]
        public static extern int SendARP(int destIp, int srcIP, byte[] macAddr, ref uint physicalAddrLen);
private void WakeFunction(string MAC_ADDRESS)
        {
            WOLClass client = new WOLClass();
            client.Connect(new IPAddress(0xffffffff), 0x2fff);
            client.SetClientToBrodcastMode();
            int counter = 0;
            //буфер для отправки
            byte[] bytes = new byte[1024];
            //Первые 6 бит 0xFF
            for (int y = 0; y < 6; y++)
                bytes[counter++] = 0xFF;
            //Повторим MAC адрес 16 раз
            for (int y = 0; y < 16; y++)
            {
                int i = 0;
                for (int z = 0; z < 6; z++)
                {
                    bytes[counter++] = byte.Parse(MAC_ADDRESS.Substring(i, 2), NumberStyles.HexNumber);
                    i += 2;
                }
            }

            //Отправляем полученный магический пакет
            int reterned_value = client.Send(bytes, 1024);
        }
 public class WOLClass : UdpClient
    {
        public WOLClass()
            : base()
        { }
        //Установим broadcast для отправки сообщений
        public void SetClientToBrodcastMode()
        {
            if (this.Active)
                this.Client.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Broadcast, 0);
        }
    }

Вот, наверное, и всё, я постарался пробежаться по основным моментам несложной, но очень интересной программы. Для статьи я наполнил эту программу еще некоторым функционалом, чтобы как-то разнообразить ее. Если кого то заинтересует — здесь есть, что взять для себя. Ниже представлен весь код:

Код XAML
<Window x:Class="Network.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="497" Width="872" Closing="Window_Closing">
    <Grid>
        <ListView Margin="12,84,12,12" Name="listView1">
            <ListView.ContextMenu>
                <ContextMenu >
                    <MenuItem Header="Копировать">
                        <MenuItem Header="IP-adress" Name="copyIP" Click="copyIP_Click" />
                        <MenuItem Header="HostName" Name="copyName" Click="copyName_Click" />
                        <MenuItem Header="Mac-adress" Name="copyMacAddress" Click="copyMacAddress_Click" />
                    </MenuItem>
                    <MenuItem Header="Очистисть список" Name="ClearList" Click="ClearList_Click" />
                    <MenuItem Header="Сохранить список"/>
                    <MenuItem Header="Действия">
                        <MenuItem Header="Удаленное включение" Name="PowerOn" Click="PowerOn_Click" />
                        <MenuItem Header="Удаленное завершение" IsEnabled="False" />
                    </MenuItem>
                    <MenuItem Header="Отмена"/>
                </ContextMenu>
            </ListView.ContextMenu>
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="IP-Адрес" DisplayMemberBinding="{Binding Path=ipAdress}" Width="200"></GridViewColumn>
                        <GridViewColumn Header="HostName" DisplayMemberBinding="{Binding Path=nameComputer}" Width="250"></GridViewColumn>
                        <GridViewColumn Header="Mac адрес" DisplayMemberBinding="{Binding Path=MacAdress}" Width="250"></GridViewColumn>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="221,15,0,0" Name="textBox1" VerticalAlignment="Top" Width="164" />
        <Label  Height="27" HorizontalAlignment="Left" Margin="219,36,0,0" Name="label1" VerticalAlignment="Top" Width="316">
            IP-адресс/Host-имя компьютера,
            
                например: 192.168.1.1
        </Label>
        <Button Content="Начать сканирование" Height="52" HorizontalAlignment="Left" Margin="12,15,0,0" Name="button2" VerticalAlignment="Top" Width="153" Click="button2_Click" />
        <Label Content="Ваш IP:" Height="28" HorizontalAlignment="Right" Margin="0,1,125,0" Name="label2" VerticalAlignment="Top" Width="50" />
        <Label Height="28" Margin="0,1,2,0" Name="label3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="117" />
        <Button Content="Проверить" Height="23" HorizontalAlignment="Left" Margin="415,15,0,0" Name="button1" VerticalAlignment="Top" Width="120" Click="button1_Click_1" />
        <ComboBox Height="23" HorizontalAlignment="Right" Margin="0,45,62,0" Name="comboBox1" VerticalAlignment="Top" Width="199" SelectionChanged="comboBox1_SelectionChanged" />
        <Grid Background="#FF9D9D9D" HorizontalAlignment="Right" Margin="0,91,-191,10" Name="rectangle1" Width="178">
            <Label Content="IP- адрес" Height="28" Margin="16,25,23,0" Name="label4" VerticalAlignment="Top" />
            <TextBox Height="23" HorizontalAlignment="Left" Margin="16,53,0,0" Name="textBox2" VerticalAlignment="Top" Width="139" />
            <TextBox Height="23" HorizontalAlignment="Left" Margin="16,124,0,0" Name="textBox3" VerticalAlignment="Top" Width="139" />
            <Label Content="HostName" Height="28" Margin="16,90,23,0" Name="label5" VerticalAlignment="Top" />
            <TextBox Height="23" HorizontalAlignment="Left" Margin="16,203,0,0" Name="textBox4" VerticalAlignment="Top" Width="139" />
            <Label Content="Mac-address" Height="28" Margin="16,169,23,0" Name="label6" VerticalAlignment="Top" />
            <Button Content="Включить" Height="23" HorizontalAlignment="Left" Margin="16,0,0,58" Name="button3" VerticalAlignment="Bottom" Width="139" Click="button3_Click" />
            <Button Content="Закрыть" Height="23" HorizontalAlignment="Left" Margin="16,0,0,19" Name="button4" VerticalAlignment="Bottom" Width="139" Click="button4_Click" />
        </Grid>
    </Grid>
</Window>



код C#
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;
using System.Runtime.InteropServices;
using System.Threading;
using System.Net.Sockets;
using System.Globalization;
using System.IO;

namespace Network
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport("iphlpapi.dll", ExactSpelling = true)]
        public static extern int SendARP(int destIp, int srcIP, byte[] macAddr, ref uint physicalAddrLen);

        List<TableHost> _host = new List<TableHost>();
        string hostname = "";
        IPHostEntry entry ;
        string[] ipToString = new string[4];


        public MainWindow()
        {
            InitializeComponent();
            
                //string[] first = adress.ToString().Split('.');
                //string[] second = IPAddress.Parse("192.168.1.0").ToString().Split('.');
            // Получение имени компьютера.
            String host = System.Net.Dns.GetHostName();
            // Получение ip-адреса.
            System.Net.IPAddress ip = System.Net.Dns.GetHostByName(host).AddressList[0];
            // Показ адреса в label'е.
            label3.Content = ip.ToString();
            ipToString = ip.ToString().Split('.');
            ADd();
        }

        string[] ipadressText;
        string[] hostnameText;
        string[] macaddressText;

        private void ADd()
        {
            string[] str = File.ReadAllLines("IPMAC.txt");
            ipadressText = new string[str.Length];
            hostnameText = new string[str.Length];
            macaddressText = new string[str.Length];
            for (int i = 0; i < str.Length; i++)
            {
                string[] s = str[i].Split('#');
                ipadressText[i] = s[0];
                hostnameText[i] = s[1];
                macaddressText[i] = s[2];
                comboBox1.Items.Add(s[1]);
            }
            
        }

        private void WakeFunction(string MAC_ADDRESS)
        {
            WOLClass client = new WOLClass();
            client.Connect(new IPAddress(0xffffffff), 0x2fff);
            client.SetClientToBrodcastMode();
            int counter = 0;
            //буффер для отправки
            byte[] bytes = new byte[1024];
            //Первые 6 бит 0xFF
            for (int y = 0; y < 6; y++)
                bytes[counter++] = 0xFF;
            //Повторим MAC адрес 16 раз
            for (int y = 0; y < 16; y++)
            {
                int i = 0;
                for (int z = 0; z < 6; z++)
                {
                    bytes[counter++] = byte.Parse(MAC_ADDRESS.Substring(i, 2), NumberStyles.HexNumber);
                    i += 2;
                }
            }

            //Отправляем полученый магический пакет
            int reterned_value = client.Send(bytes, 1024);
        }


        private void GetInform(string textName)
        {
            string IP_Address = "";
            string HostName = "";
            string MacAddress = "";

            try
            {
                //Проверяем существует ли IP
                entry = Dns.GetHostEntry(textName);
                foreach (IPAddress a in entry.AddressList)
                {
                    IP_Address = a.ToString();
                    break;
                }

                //Получаем HostName
                HostName = entry.HostName;

                //Получаем Mac-address
                IPAddress dst = IPAddress.Parse(textName); 

                byte[] macAddr = new byte[6];
                uint macAddrLen = (uint)macAddr.Length;

                if (SendARP(BitConverter.ToInt32(dst.GetAddressBytes(), 0), 0, macAddr, ref macAddrLen) != 0)
                    throw new InvalidOperationException("SendARP failed.");

                string[] str = new string[(int)macAddrLen];
                for (int i = 0; i < macAddrLen; i++)
                    str[i] = macAddr[i].ToString("x2");

                MacAddress = string.Join(":", str);

                //Далее, если всё успешно, добавляем все данные в список, после чего выводим всё в ListView
                Dispatcher.Invoke(new Action(() =>
                {

                    _host.Add(new TableHost() { ipAdress = IP_Address, nameComputer = HostName, MacAdress = MacAddress });
                    listView1.ItemsSource = null;
                    listView1.ItemsSource = _host;
                }));
            }
            catch { }
           
        }


        private void button1_Click(object sender, RoutedEventArgs e)
        {

            //string message = "";
            //Print(GetIP(textBox1.Text), GetHostName(textBox1.Text), GetMac(message));
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            int i = int.Parse(ipToString[0]);
            int j = int.Parse(ipToString[1]);
                {
                    for(int k = 0;k<6;k++)
                    {
                        for (int m = 0; m < 254; m++)
                        {
                            Thread _thread = new Thread(() => GetInform(string.Format("{0}.{1}.{2}.{3}", i.ToString(), j.ToString(), k.ToString(), m.ToString())));
                            _thread.Start();                            
                        }
                    }
                }
               
        }

        private void PowerOn_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                WakeFunction(_host[listView1.SelectedIndex].MacAdress.ToString().Replace(":", ""));
                MessageBox.Show("Операция выполнена успешно!", "Внимание!", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch { MessageBox.Show("Запрос некорретный!","Внимание!Ошибка!",MessageBoxButton.OK,MessageBoxImage.Error); }
        }

        private void ClearList_Click(object sender, RoutedEventArgs e)
        {
            _host.Clear();
            listView1.Items.Refresh();
        }

        private void copyIP_Click(object sender, RoutedEventArgs e)
        {
            Clipboard.SetText(_host[listView1.SelectedIndex].ipAdress.ToString());
        }

        private void copyName_Click(object sender, RoutedEventArgs e)
        {
            Clipboard.SetText(_host[listView1.SelectedIndex].nameComputer.ToString());
        }

        private void copyMacAddress_Click(object sender, RoutedEventArgs e)
        {
            Clipboard.SetText(_host[listView1.SelectedIndex].MacAdress.ToString());
        }

        private void button1_Click_1(object sender, RoutedEventArgs e)
        {
            GetInform(textBox1.Text);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            StreamWriter write = new StreamWriter(@"C:\Users\***\IPMAC.txt", true);

            for (int index = 0; index < _host.Count; index++)
            {

                if (!macaddressText.Contains(_host[index].MacAdress))
                    write.WriteLine(_host[index].ipAdress + "#" + _host[index].nameComputer + "#" + _host[index].MacAdress);
            }
            write.Close();
        }

        void P()
        {
            for (double i = -192; i < 10; i += 0.004)
            {
                Dispatcher.Invoke(new Action(() =>
                {
                    rectangle1.Margin = new Thickness(0, 101, i, 10);
                }));

            }//12,0,12,1


        }

        private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //ii = rectangle1.Width;
            textBox2.Text = ipadressText[comboBox1.SelectedIndex];
            textBox3.Text = comboBox1.SelectedItem.ToString();
            textBox4.Text = macaddressText[comboBox1.SelectedIndex];
            Thread thread = new Thread(P);
            thread.Start();
        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                WakeFunction(textBox4.Text.Replace(":", ""));
                MessageBox.Show("Операция выполнена успешно!", "Внимание!", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            catch { MessageBox.Show("Запрос некорретный!", "Внимание!Ошибка!", MessageBoxButton.OK, MessageBoxImage.Error); }
        }

        private void button4_Click(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(CLose);
            thread.Start();
        }

        void CLose()
        {
            for (double i = 9; i > -193; i -= 0.004)
            {
                Dispatcher.Invoke(new Action(() =>
                {
                    rectangle1.Margin = new Thickness(0, 101, i, 10);
                }));

            }//12,0,12,1
        }
    }

    class TableHost
    {
        public string ipAdress { get; set; }
        public string nameComputer { get; set; }
        public string MacAdress { get; set; }
    }

    public class WOLClass : UdpClient
    {
        public WOLClass()
            : base()
        { }
        //Установим broadcast для отправки сообщений
        public void SetClientToBrodcastMode()
        {
            if (this.Active)
                this.Client.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Broadcast, 0);
        }
    }
}


Теги:
Хабы:
+11
Комментарии32

Публикации

Истории

Работа

Ближайшие события