Home TürkçeC# Bilgisayarınızı C# ile uzaktan başlatın, Wake-On-Lan

Bilgisayarınızı C# ile uzaktan başlatın, Wake-On-Lan

by Fatih Boy
12 comments

WoL keyboard   Geçtiğimiz günlerde kullandığım netbook’un daha fazla yapmak istediğim işleri desteklemeyeceğine karar vererek güçlü bir masaüstü bilgisayar almaya karar verdim. Güzel bir yapılandırma ile Windows Server 2008 R2 Core ve üzerine de Hyper-V kurduktan sonra sanal makinelerimi ayarlayarak uzak masaüstü bağlantısı ile çalışmaya başladım. Sonrasında bir adım daha ileri giderek modem üzerinden gerekli yönlendirmeleri de yaparak ev dışında bulunduğum zamanlarda dahi belgelerime/çalışmalarıma ulaşabilmeye başladım.
   Buraya kadar her şey normal olmasına karşın yurdum elektrik altyapısını göz ardı ettiğimi acı bir deneyimle hatırladım (ya da hatırlattılar mı demeliyim :)). Haliyle evdeki elektrik kesintisi sonrasında gün içerisinde bilgisayarıma ulaşamadım. Tembel bir yazılımcının her zaman için iyi bir yazılımcı olacağını hatırlayalım, bir daha böyle bir şey yaşamamak, evdeyken bile bilgisayarın başına gitmeden başlatabilmek ne güzel olur diye düşünmeye başladım. Şanslıyım ki bilgisayarımın WOL (Wake-On-Lan) desteği var, yazdığım küçük bir uygulama ile bilgisayarımın başında olmaksızın gerek internet gerekse de intranetten bilgisayarımı başlatabiliyorum. Aşağıda, yazdığım bu kısa programım ve Wake-On-Lan hakkında bilgilere ulaşabilirsiniz.
   Uygulamaya geçmeden önce isterseniz Wake-On-Lan (diğer isimleri ile Wake On WAN, Remote Wake-up, Power On By LAN, Power Up By LAN, Resume by LAN, Resume on LAN, Wake Up On LAN) nedir birlikte görelim.
   Wake-On-Lan, en kaba anlatımıyla, network üzerinden gönderilen bir paket ile bir bilgisayarın çalışması için geliştirilmiş bir Ethernet bilgisayar ağ standardıdır. İşletim sisteminden bağımsız olarak, donanım seviyesinde desteklenen Wake-On-Lan standardında, anakartın ve ağ ara yüzünün (network kartı) bu özelliği destekliyor ve aktive edilmiş olması gerekmektedir. Çalışma prensibi olarak, biraz önce de belirttiğim gibi, ağ üzerinden gönderilen bir paket sonucunda sistem çalışır duruma geçmektedir. Tamamen kapalı durumdaki bir sistemin ağ üzerinden gelen paketleri işlemesinin mümkün olmadığı düşünecek olursak bilgisayarınızı öncelikle elektriğe bağlı ve düşük güç tüketiminde, bir nevi uyku modunda,  çalışıyor olması gerekmekte. Sistemin gelen her ağ paketi ile çalışır duruma gelmesini önlemek adına standartta özel/sihirli paket (magic packet) tanımlanmıştır. Ağ  ara yüzü sistem kapalı durumda iken teslim aldığı her bir paketi inceleyerek bu sihirli paketin ulaşıp ulaşmadığını kontrol etmekte ve uygun paket ulaştığında sistemi  çalıştırmaktadır. OSI modelinde 2. katmana yerleştirebileceğimiz Wake-On-Lan standardı bu özelliği nedeniyle OSI modelinde 3. katmanda yer alan IP adresi üzerinden çalışmamaktadır. İşletim sisteminin dahi devrede olmadığı ve sistemin neredeyse kapalı olduğu uyku halinde zaten bir IP adresinin kullanılabilir olması da pek mümkün değildir.
   Peki sisteme sihirli paketi IP adresini kullanarak ulaştıramıyorsam nasıl ulaştırabilirim? Yapılması gereken, sihirli paketin ağ üzerinde yer alan tüm bilgisayarlara iletilerek doğru bilgisayarın bu paketi kabul ederek çalışır duruma geçmesidir. Ağ üzerinde yer alan tüm bilgisayarlara bir paket göndermek, bir paketin yayınını yapmak dediğimde zaten pek çoğunuz kullanılması gereken yöntemin Broadcast olduğunu fark edecektir. Sistem hemen çalışır duruma gelerek pakete yanıt veremiyor olması nedeniyle TCP üzerinden göndermek yerine yanıt beklemediğimiz UDP tercih edilmesi oldukça normaldir. Tüm resmi bir araya getirdiğimizde sihirli paketimizi hedef bilgisayara iletmek için yapılması gereken ağ üzerinden bir UDP broadcast’i gönderilmesidir. Wake-On-Lan konusunda sıklıkla hataya düşülen nokta, sistemin tamamen broadcast üzerinden çalışabiliyor olduğunun düşünülmesidir. Yapılan broadcast sadece sihirli paketi hedef makineye ulaştırmak için bir araçtır. Örneğin; internete bağlı bir modem üzerinden yapılacak bir yönlendirme sonrasında dış ip adresinize yapacağını bir sihirli paket gönderimi de işe yarayacaktır. Ağ ara yüzü herhangi bir port üzerinden gelecek olan sihirli paket ile sistemi çalışır duruma getireceğinden broadcast için kullanacağınız portun bir önemi bulunmamaktadır, herhangi bir port tercih edilebilir.
   Teorik olarak sistemin nasıl işlediğini gördükten sonra bunu C# ile hayata geçirmek için yayını yapılan sihirli paketin içeriğini bilmemiz gerekli. Sihirli paketin ilk 6  byte’ı 255 (yani hexedecimal FF) olmalıdır. 6 byte’lık 255’in devamında hedef bilgisayarın 48-bitlik MAC adresi (olasılığı düşürmek adına) 16 kez tekrar ediliyor olmalıdır. Ağ ara yüzü, gönderim protokolünden bağımsız olarak, teslim aldığı paketleri kontrol ederek paket içerisindeki herhangi bir noktada bu kombinasyonu bulması halinde sistemi başlatacaktır.

Wake-On-Lan Sihirli Paket yapısı
   Sistemin işleyişini ve sihirli paketin yapısını öğrendikten sonra bu işi yapacak olan C# kodunu yazmak aslında oldukça kolay. Öncelikle byte dizisi olarak MAC adresini bir değişkende saklamalıyız. Örnek olması adına sanal bir MAC adresi olarak 1A-4F-F5-4F-98-AA değerini kullanıyorum. Gerçek sistemlerde kullanmanız gereken MAC adresini hedef bilgisayarda komut satırından çalıştıracağınız ipconfig /all komutu ile öğrenebilirsiniz.

var bitMacAdresi = new byte[] { 0x1A, 0x4F, 0xF5, 0x4F, 0x98, 0xAA };

   Ardından yayınlanacak olan paketin içeriğini tutacak ikinci bir byte dizi oluşturarak ilk 6 byte’ını 0xFF ile doldurmalıyız;

var sihirliPaket = new List<byte>(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });

   paketimizin kalan kısmına ise 16’lık bir döngü ile MAC adresini eklemeliyiz;

for (int i = 0; i < 16; i++) {
sihirliPaket.AddRange(bitMacAdresi);
}

   Son adımda ise, oluşturduğumuz sihirli paketi ağ üzerinden yayınlamalıyız. Yayınlama için System.Net.Sockets isim uzayında yer alan UDPClient sınıfı kullanılabilir;

var istemci = new UdpClient();
istemci.Connect(IPAddress.Broadcast, 80);
istemci.Send(sihirliPaket.ToArray(), sihirliPaket.Count);

   Her ne kadar örneğimde UDP yayınını 80. port üzerinden yapıyor olsam da, siz herhangi başka bir portu kullanmakta serbestsiniz.

   Yukarıdaki örnek hedef bilgisayarın uygulamanın çalışacağı makine ile aynı alt ağ’da (subnet) olduğunu varsayarak, bu alt ağa yayın yapmaktadır. Bazı senaryolarda hedef bilgisayarın uygulamanın çalışacağı alt ağdan farklı bir alt ağ’da bulunuyor olması söz konusudur. Bu gibi durumlarda ilgili alt ağ’a ait yayın adresi hesaplanarak sihirli paket bu adrese gönderilmelidir. Aşağıda sizlerle paylaştığım static YayinAdresiniHesapla fonksiyonu hedef makinenin ip adresi ve alt ağ maskesi verilerek yayının yapılacağı ip adresini hesaplamaktadır;

public static IPAddress YayinAdresiniHesapla(IPAddress hedefMakineIP, IPAddress altAgMaskesi) {
    var ipAdresBitleri = hedefMakineIP.GetAddressBytes();
    var altAgMaskesiBitleri = altAgMaskesi.GetAddressBytes();

    var yayinAdresi = new byte[ipAdresBitleri.Length];
    for (int i = 0; i < yayinAdresi.Length; i++) {
        yayinAdresi[i] = (byte)(ipAdresBitleri[i] | (altAgMaskesiBitleri[i] ^ 255));
    }

    return new IPAddress(yayinAdresi);
}

   Bu fonksiyon kullanılırken hedef makineni ip adresi bilinmiyorsa, ip adresi olarak hedef makine ile aynı ağ ayda bulunan bir başka makine ip’si verilerek de yayının yapılacağı adres bulunabilir. Aşağıda, şimdiye kadar sizlerle paylaştığım kodları toplu halde bulabilirsiniz;

class Program {
    static void Main(string[] args) {
        var hedefMakineIP = "192.168.2.12";
        var altAgMaskesi = "255.255.255.0";
        var macAdresi = "1A-4F-F5-4F-98-AA";

        var yayinAdresi = YayinAdresiniHesapla(IPAddress.Parse(hedefMakineIP), IPAddress.Parse(altAgMaskesi));

#region Mac adresini parse et
        var hexMacAdresi = long.Parse(macAdresi.Replace("-", string.Empty), NumberStyles.HexNumber, CultureInfo.CurrentCulture.NumberFormat);
        var bitMacAdresi = BitConverter.GetBytes(hexMacAdresi);
        Array.Reverse(bitMacAdresi);
#endregion

        #region Sihirli paketi oluştur
        var sihirliPaket = new List<byte>(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });

        for (int i = 0; i < 16; i++) {
            sihirliPaket.AddRange(bitMacAdresi);
        } 
        #endregion

        #region Sihirli paketi yayınla
        var istemci = new UdpClient();
        istemci.Connect(yayinAdresi, 80);
        istemci.Send(sihirliPaket.ToArray(), sihirliPaket.Count);  
        #endregion
    }

    public static IPAddress YayinAdresiniHesapla(IPAddress hedefMakineIP, IPAddress altAgMaskesi) {
        var ipAdresBitleri = hedefMakineIP.GetAddressBytes();
        var altAgMaskesiBitleri = altAgMaskesi.GetAddressBytes();

        var yayinAdresi = new byte[ipAdresBitleri.Length];
        for (int i = 0; i < yayinAdresi.Length; i++) {
            yayinAdresi[i] = (byte)(ipAdresBitleri[i] | (altAgMaskesiBitleri[i] ^ 255));
        }

        return new IPAddress(yayinAdresi);
    }
}

    Örneğimiz ip adresi ve alt ağ maskesi ikilisi verilerek intranet üzerinden çalıştırılabilir. Internet üzerinden bir bilgisayarı başlatmak istiyorsak ise öncelikli bu bilgisayarın bağlı olduğu modem üzerinden kullanılacak olarak port için NAT yönlendirmesi ve firewall ayarlarının yapılmış olması gereklidir. Bu ayarların yapılmasından sonra doğrudan ip adresine gönderim yapmak için ip adresi ile birlikte 255.255.255.255 alt ağ maskesi kullanılmalıdır.

    Konuyla ilgili olarak düşülmesi gereken son not ise; donanımsal olarak anakart ve ağ arayüzünüzün Wake-On-Lan özelliğinin aktif edilmiş olması gerektiğidir.

Ağ arayüzün özellikler ekranında Wake-On-Lan seçeneğinin aktif hale getirilmesi

   Windows yüklü sistemlerde bu ayar cihaz yöneticisi üzerinden ağ arayüzünüzün özellikleri diyaloguna gelerek bu diyalogda yer alan güç yönetimi sekmesinde "bu aygıt bilgisayarı başlatsın" seçeneği seçilerek yapılabilir.

Şu Yazıları da Sevebilirsiniz

12 comments

Gökhan 23 Aralık 2010 - 21:39

Eline sağlık. Güzel bir yazı olmuş. Paylaşımın için teşekkürler.

Reply
Mert 16 Nisan 2012 - 16:06

Fatih hocam öncelikle ellerinize sağlık. Tcp ile bunu nasıl gönderiyoruz. Ben yapamadım da yardımlarınızı bekliyorum.

Reply
Fatih Boy 17 Nisan 2012 - 20:48

Merhaba Mert,
Wake-On-Lan özelliği temelde OSI modeli 2. katmanı olan DataLink katmanında gerçekleşmektedir ve ağ yayın adresini (broadcast address) kullanarak ağa bağlı tüm bilgisayarların NIC’lerine özel bir paket yollamaktadır. Bu özel paketin tüm ağa yayınlanmasında UDP kullanılmakta ve herhangi bir IP kullanımı söz konusu değildir. Bu nedenlerden dolayı da TCP üzerinden bu paket gönderilememektedir. Buna tek istisna alt ağ yönlendirmeli yayınlar (Subnet Directed Broadcasts (SDB)) olabilir; fakat bunun için de ağ üzerinde gelen paketleri işleyip broadcastlare dönüştürebilen özel router’ların bulunması gerekli.

Reply
Mert 18 Nisan 2012 - 14:10

Teşekkür ederim Fatih Bey oldukça açıklayıcıydı.

Reply
akif 17 Aralık 2014 - 20:44

hocam merhaba bu işlem local olarakta uygulanabilirmi…

Reply
Fatih Boy 17 Aralık 2014 - 21:25

Merhaba Akif, evet Wake-On-Lan işlemi için paket local network üzerinden gönderilebilmekte.

Reply
akif 18 Aralık 2014 - 14:42

hocam bu işlemi tek bir pc için uygulamak istiyorum yardımcı olursanız sevinirim

Reply
Fatih Boy 2 Ocak 2015 - 14:37

Merhaba Akif,
Yazımda paylaştığım yöntem sadece tek bir bilgisayarın ağ üzerinden uyandırılmasını sağlamaktadır. Bu sebeple, paylaştığım adımları takip ederek tek bir bilgisayarı uzaktan uyandırabilirsin.

Reply
Serkan 27 Kasım 2015 - 17:05

Ben bunu console.aplication da çalıştırıyorum yanlışmı acaba?

Kodlar aşağıda fakat classlarda problem oluyor aynı isimden olduğunu düşünüyorum ismini değiştirip heryerde uyguladıktan sonra da Main “static void Main(string[] args)” kısmında hata veriyor.

namespace PC
{
class Program
{
static void Main(string[] args)
{
var bitMacAdresi = new byte[] { 0xAE, 0xE0, 0x10, 0xD0, 0x43, 0xF1 };
var sihirliPaket = new List(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });
for (int i = 0; i < 16; i++)
{
sihirliPaket.AddRange(bitMacAdresi);
}
var istemci = new UdpClient();
istemci.Connect(IPAddress.Broadcast, 80);
istemci.Send(sihirliPaket.ToArray(), sihirliPaket.Count);
}

public static IPAddress YayinAdresiniHesapla(IPAddress hedefMakineIP, IPAddress altAgMaskesi)
{

var ipAdresBitleri = hedefMakineIP.GetAddressBytes();
var altAgMaskesiBitleri = altAgMaskesi.GetAddressBytes();
var yayinAdresi = new byte[ipAdresBitleri.Length];
for (int i = 0; i < yayinAdresi.Length; i++)
{
yayinAdresi[i] = (byte)(ipAdresBitleri[i] | (altAgMaskesiBitleri[i] ^ 255));
}
return new IPAddress(yayinAdresi);
}

class Program1
{
static void Main(string[] args)
{

var hedefMakineIP = "192.168.2.12";
var altAgMaskesi = "255.255.255.0";
var macAdresi = "AE-E0-10-D0-43-F1";

var yayinAdresi = YayinAdresiniHesapla(IPAddress.Parse(hedefMakineIP), IPAddress.Parse(altAgMaskesi));

#region Mac adresini parse et

var hexMacAdresi = long.Parse(macAdresi.Replace("-", string.Empty), NumberStyles.HexNumber, CultureInfo.CurrentCulture.NumberFormat);

var bitMacAdresi = BitConverter.GetBytes(hexMacAdresi);

Array.Reverse(bitMacAdresi);
#endregion

#region Sihirli paketi oluştur

var sihirliPaket = new List(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF });

for (int i = 0; i < 16; i++)
{

sihirliPaket.AddRange(bitMacAdresi);

}

#endregion

#region Sihirli paketi yayınla

var istemci = new UdpClient();
istemci.Connect(yayinAdresi, 80);

istemci.Send(sihirliPaket.ToArray(), sihirliPaket.Count);

#endregion

}

public static IPAddress YayinAdresiniHesapla(IPAddress hedefMakineIP, IPAddress altAgMaskesi)
{

var ipAdresBitleri = hedefMakineIP.GetAddressBytes();

var altAgMaskesiBitleri = altAgMaskesi.GetAddressBytes();

var yayinAdresi = new byte[ipAdresBitleri.Length];

for (int i = 0; i < yayinAdresi.Length; i++)
{

yayinAdresi[i] = (byte)(ipAdresBitleri[i] | (altAgMaskesiBitleri[i] ^ 255));

}

return new IPAddress(yayinAdresi);

}

}

}

}

Reply
Serkan 27 Kasım 2015 - 17:08

(MAC Adresi ve ip adresi örnektir)

Reply
[email protected] 27 Ocak 2016 - 13:10

fatih hocam yazdıgınız c# kodunu denedim ama calısmadı aynı alt agda oldugum için YayinAdresiniHesapla() yi iptal ettim ve istemci.Connect(altAgMaskesi,80); seklinde calıstırdım ama bu sefer de yuva gecerli degıl gibi bi hata verdi yardımcı olabılır mısınız?

Reply
fatih 31 Ocak 2016 - 13:17

Merhaba [email protected],
istemci.Connect(altAgMaskesi,80); şeklindeki kod ile doğrudan bir bilgisayarın 80 portuna bağlanmaya çalışıyorsun. Bu ip’de bir bilgisayar, dolayısıyla da dinlenen bir soket olmadığı için bağlantı hatası alman beklenen bir durum. Diğer yandan, yapman gereken broadcast adresi üzerinden ağdaki tüm bilgisayarlara udp üzerinden sihirli paketi göndermek. Bu sebeple makalede istemci.Connect(IPAddress.Broadcast, 80); şeklinde broadcast adresine bağlantı açtım. Kodun çalışmaması konusunda ise, öncelikle hedef bilgisayarın wake-on-lan ayarlarını kontrol etmende fayda var. Bilgisayarın ağ üzerinden uyandırılabilir olarak yapılandırılması önemli. Sonrasında ikinci, üçüncü bir örnek kod ya da uygulama ile bilgisayarın uyandırılabildiğini teyit etmekte fayda var.

Reply

Leave a Comment

* Bu formu kullanarak, verilerinizin bu web sitesi tarafından saklanması ve kullanılmasını kabul ediyorsunuz.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Bu web sitesi deneyiminizi geliştirmek için çerezleri kullanır. Bunu kabul ettiğinizi varsayacağız, ancak isterseniz vazgeçebilirsiniz. Kabul Et Daha Fazla Bilgi