802.11 Kanal değiştirme simülasyonu (Omnet++ )

Bu çalışmada Ad-Hoc modunda çalışan bir 802.11 modülünün haberleşme halinde iken kanal değiştirme senaryosunu gerçekleştireceğiz. Kanal değişimini ise Omnet++ ortamında C++ ile yazdığımız kod parçası sayesinde gerçekleştireceğiz.

Şekil 1 – Ağ Yerleşimi

Gelelim Senaryomuza: 802.11 alt yapısını kullanrak Ad-Hoc modda UDP haberleşmesi yapan iki adet cihazımız var. Bu iki cihazda mobileHost[0] 100 ms aralılarla 1000Bayt lık bir UDP paketi gönderiyor. 100 saniye süren simulasyon boyunca 10 saniye aralılarla göndericinin MAC katmanında kanalı değiştiriliyor. Kanal haberleşmenin olduğu 5. kanalda başlarken 10 saniye aralıklarla 5. ve 0. kanal arasında değiştiriliyor.

## file name: omnetpp.ini
sim-time-limit = 100s
**.mobileHost[0].numApps = 1
**.mobileHost[0].app[0].typename = "UdpBasicApp"
**.mobileHost[0].app[0].destAddresses = "mobileHost[1]"
**.mobileHost[0].app[0].destPort = 1000
**.mobileHost[0].app[0].messageLength = 1000B
**.mobileHost[0].app[0].sendInterval = 0.1s

**.mobileHost[1].numApps = 1
**.mobileHost[1].app[0].typename = "UdpSink"
**.mobileHost[1].app[0].localPort = 1000

**.mobileHost[*].wlan[0].radio.channelNumber = 5

Kanal değiştirme.

802.11 de oluğu gibi omnet oratamında kanal değiştirme 2. katmanda yönetiliyor. Mac katmanında oluşturulan “physicallayer::Ieee80211ConfigureRadioCommand” mesajnı radyo modülüne göndererek yapılır. Komutta kanal numarası alanı istenilen kanal olarak atanır ve oluşturulacak Request’e ControlInfo olarak eklenir ve gönderilir.

Şekil 2 – 2. katman Modülleri
void Ieee80211Mac::handleSelfMessage(cMessage *msg)
{
    //ASSERT(false);
    Ieee80211Radio * myradio = check_and_cast<Ieee80211Radio *>(this->radio);
    Ieee80211TransmitterBase *ieee80211Transmitter = const_cast<Ieee80211TransmitterBase *>(check_and_cast<const Ieee80211TransmitterBase *>(myradio->getTransmitter()));
    int channel = ieee80211Transmitter->channel->getChannelNumber();
    if(channel==5)
        channel=0;
    else
        channel=5;
    physicallayer::Ieee80211ConfigureRadioCommand *conf =  new Ieee80211ConfigureRadioCommand();
    conf->setChannelNumber(channel);

    auto request = new Request("configureRadioMode", RADIO_C_CONFIGURE);
    request->setControlInfo(conf);
    take(request);
    sendDown(request);
    scheduleAt(simTime() + 10.0, msg); // Tekarar değişimi tetikler.
}

Radyo katmanı ilgili komutu alır ve trensmiite ve reciever modüllerini ayrı ayrı istenilen kanala ayarlar.

Sonuçlar

Simulasyon sonucu mobilHost[0] için kanal değilşim ve mobilHost[1] için alınan PaketByte verisi tek garfik te çizdirildiğinde aşağıdaki sonuç elde edilmektedir. Şekil 3 tende görüldüğü üzere kanl değişiminden sonra tekrardan veri gönderimi başlayana kadar biraz süre geçmekte ve haberleşme gecikmeli olarak başlayabilmektedir. Burada sebep Routing Algoritması AODV’nin (ve dolayısıyla link katmanının) tekrardan link kurulumunu sağlaması için geçen süredir.

Yine şekil 1 de görüldüğü üzere 1000 paket gönderilmiş fakat 479 paket alınmıştır. Bir paket alınamadan simülasyon bittiği için 480 paket kabul edilmelidir. Sonuç olarak Yarı yarıya iletim sağlanması beklenirken 20 paket iletim hatası vardır. Başlangıç hariç 4 kez tekrardan haberleşme kanalına geçildiği düşünülürse 20/4 ten her tekrardan link kurulumu 5 paket süresi yani 500 ms sürmekte ve bu aralıkta 5 paket kaybı olmaktadır.

Sonuç
Şekil 3 – Sonuç

Ek bilgi: Simülasyon Akışı

Senaryoyu oluşturmak için self message yöntemi kullanılmıştır. Bunun için Ieee80211Mac.cc dosyasında init fonksiyonuna aşağıdaki kod bloğu eklenmiştir ve Her bir mesaj tekrardan 10 saniye sonra gelecek bir mesajı tetiklemektedir.

    if(strcmp(this->getParentModule()->getParentModule()->getFullName(),"mobileHost[0]")==0)
    {
        cMessage *msg = new cMessage("tecrubedenkatreler.com");
        scheduleAt(simTime()+10.0, msg);
    }

Bir Probleme nasıl yaklaşmalı – Veri yapıları – Algoritma – Ödev

Bir bilgisayar programcısının ödeve(projeye) bakması gereken açıyı anlatmya çalıştım.

İçerik :

  1. Ödev dökümanı nasıl okunlmalı,
  2. ekrana şekil bastırma (çıktıyı düzenleme)
  3. Nesneye dayalı programlama,
  4. cout aşırı yükleme (function overloading)- 35:52 dk,
  5. hep bellek bölgesi (new)
  6. eden çöpleri toplamalıyız: (delete)
  7. Örnek bir uygulama incelendi

Birkaç aksaklık (girişte biraz heycan, static 🙂 ) olsada, faydalı olması dileğiyle…..

Dökümanlar:
https://www.dropbox.com/sh/jwar422ozjtxo36/AAAH0osmak05V8rJTuWbZ3ZBa?dl=0

Not: İlk anlatılan dökümanda(ödev dokumanı): Sepet içinde çivilerin bulunmsa durumu değilde, Sepetlerin Çiviye asılamsı durumu istenmiş görselde de gösterilmiş. Yani harfler Çivi değil.

çivi

Keywordler: Veri yapıları, Ödev1, Sakarya Üniversitesi, Bir yaklaşım, Problem Çözme, Algortima geliştirme, Ödev yapmak, Bilgisayr Mühendisliği, c++

İşaretçiler namı diğer “Pointer”

Bu yazımızda işaretçilerden bahsedeceğim.                       İşaretçi= Adres tutucu=Pointer;

       İşaretçiler bellekten aldığınız yerin adresini tutmada kullanılır. Bir işaretçiyi “ int *pIsaretciAdi; ” şeklinde kodlayarak oluştururuz. İşaretçilerin başlarına p harfini koyarız ki onun işaretçi olduğunu unutmayalım. Sizde bunu standart haline getirseniz iyi olur.

işaretçi

  1. Şekilde görüldüğü üzere ilk verilen tip pointerin değil tutulmak istenen tipi işaret eder bu tip: char, int, double… olabilir. Fakat pointerin tipi herzaman “int” dir
  2. Yıldız sayısı arttıkça pointerin derecesi artar. Peki  ya bu ne demek? Yeni başladıysanız sizin için önemli değil fakat pointerıda bir pointerda tutma ihtiyacı hissediyorsanız burada yıldısayısı arttıyor. (bir dahaki yazımda bu konuyu anlatacağım)
  3. işaretçiye vermek istediğiniz ism başına p koymak ide’lerde işaretçileri ayırt etmenizi sağlar.

İşaretçiler bellekten aldığınız yerin adresini tutmak için c/c++ dilinde vardırlar.
Stack (dinamik olmayan) hafızada oluşturduğumuz değişkenlerin adresleri değişken adında tutulduğu için zaten bellidir o yüzden tekrar bir işaretçiye genelde ihtiyaç duyulmaz. Fakat kullanmakta mümkündür.

Örnek verecek olursak

int a;  // dediğimizde stackden yer almış oluruz ve
        //bunun adresini zaten “a” değişkeni tutuyordur.
int* pA=&a;  // şeklinde a’nın adresini yinede tutabiliriz.

Fakat dikkat edilmesi gereken bazı hususlar vardır. Bir stack verisi kod bloğu bittiğinde silinir.

Yani

{
    int a=5;
    int* pA=&a;
    return pA;
}

Diyerek döndürdüğünüz pointerın (pA)  tuttuğu adrese erişmek istediğinizde kod bloğu bitmiş olan a değişkeninin yeri boşaltılmış (serbest bırakılmış) olacağından hatalı erişim sağlamış olacaksınız, sadece hatalı olsa iyi belki o hücreye başka programlar tarafından farklı değerler yazılmış olma ihtimali ile karşılaşacak, yanlış değerle işlem yapacaksınız yada başka programın kullandığı hücreyi kullanarak diğer programaın akışını bozacaksınız.

Bu durumu gidermek istersek pA pointerının tuttuğu adresi (yeri) de heapten almalıyız.

{
    int* pA= new int;
    *pA=5;
    return pA;
}

Bu ise yukarıda görüldüğü gibi “ int * pA= new int; “ şeklinde alınır.

Burada yapılacak en büyük hata tek int’lik yer alınmasına rağmen

    *(pA+1)=25;     /*veya*/   cout<<pA[2]; // ikiside hatalı

Sıfırıncı hücre dışındaki hücrelere erişimin sağlanmasıdır. Bu tamamen sizin kontrol etmeniz gereken bir durumdur.(genelde bu hata döngülerde programcının gözünden kaçar)

Şu unutulmamalı ki her pointer bir adres tutar. Ve işaretçinin adı yazıldığında tuttuğu adrese, başına “*” koyduğunuzda adresteki değere, başına “&” koyduğunuzda ise işaretçinin adresine ulaşırsınız.
Adsız

İşaretçiye ihtiyaç stack (dinamik) hafızadan alınan verilerin adreslerinin sadece bir seferliğine yani alınırken erişilir olmasından kaynaklanır.

new int[2];

Yazılması durumunda hafızadan 2 integerlik yer alınacak new fonksiyonu tarafından dizinin ilk adresi döndürülecektir fakat siz bu adresi tutmazsanız size ait olan yere tekrardan ulaşamazsınız.
İşte bu dönen adresleri tutmak için oluşturulmuş tipler pointerlardır.

int* pA= new int[2]; // 2 integer kadar yer alındı ve
                     //dönen adres pA pointerına atandı.
*pA=5;               // ilk adreste bulunan yere 5 atandı.
pA[1]=7;		 // ikinci adreste bulunan yere 7 atandı

Burada atama işleminde pointer iki şekilde kullanılmıştır.
a) “*pA” pA bir adres tutucusuydu, önüne yıldız (*) konulduğunda o adresteki veriye erişim sağlanmış olur.
a. Diğer hücrelere erişmek için ise *pA, *(pA+1), *(pA+2), *(pA+3)… şeklinde kodlanır.
b. Buradaki “pA+1” toplanan sayı yani +1 diğer değişkene geçmek demekti. Değişkenin türü int ise ,integer 4 baytdir, (pA’nın tuttuğu adres+4) anlamına gelir.
1
b) “pA[1]” Adres tutan pA pointerina indis verilince derleyici içine erişilmek istediğini anlıyor ve [ ] indisin içindeki değer ne ise o indisin ifade ettiği hücreye işlem yapmaya başlıyor.
a. Diğer hücrelere erişmek için pA[0], pA[1], pA[2], pA[3]… gibi kullanılabilir. Resimde görmek için tıklayınız.

Küçük bir program üzerinden anlatmaya devam edelim. Bu program aşağıda yazılan işleri sırası ile yapacaktır:
1. Stackden bir pointer yeri alacak
2. Sonra o pointer’a heapten aldığımız 5 int’lık yerin ilk adresini tutacak
3. Bu 5 elemanlı dizinin 5 elamanına (indisi^4) atanacak (ilk for)
4. Ve sonra Değer ler tek tek bastırılacak. (ikinci for)

Pointer-Örnek:

#include<iostream>

using namespace std;

int main ()
{
	int* pIsaretci= new int [5];

	for (int i = 0; i < 5 ; i++)
	{
		*(pIsaretci+i)=i*i*i*i;   // i^4= i*i*i*i;
	}

	for (int i = 0; i < 5; i++)
	{
		cout<<"Deger "<<i<<"= "<< pIsaretci[i]<<endl;
	}
	return 0;
}
 

2
Resim: Program ekran çıktısı
Uygulamada işaretçi ile olan iki erişim yöntemini de kullandık.
1. *(pIsaretci+i)
2. pIsaretci[i]
Tek dereceli işaretçilerde kapalı parantezli yöntem daha anlaşılır ve kullanışlı oluyor.

Tüm içerik Abdullah Salih BAYRAKTAR tarafından hazırlanmıştır.