|
C# ile Network Programlama-2 |
|
Gönderiliyor lütfen bekleyin... |
|
|
Merhabalar, Network programlama yazı
dizisinin ikincisine başlamadan önce konunun daha anlaşılır olması için birinci
yazıyı okumanızı tavsiye edirim.
Network’de yani haberleşmede ne nasıl oluyor bunların mantığını, nasıl
çalıştığını, protocollerin nasıl ve hangi safhalarda işlediğini bilmeden
network yazılımı geliştirmemiz zor olucaktır. Örneklerin kullanılabilirliği (internet
çıkışları) açısından
uygulamaları Tcp protocolü üzerinden geliştirmeye çalıştım. Bu protocolün internet
uygulamalarında kullanıldığından bahsetmiştim. Birde OSI referans modeli
ile ne yaptığımızın özüne inelim.Aşağıda meşhur OSI modelinin yapısını
görebilirsiniz.
Application>>>>Şuanda
bu katmanda çalışmaktayız. |
Network
yazılımı geliştirirken bu katman bizim kullandığımız
katmandır. |
Presentation |
Application
katmanının uzantıları, plug bilgilerinin tutulduğu
katmandır. |
Session |
Veri
girişlerinde gelen verilerin kaydedilmesinin sağlandığı
katmandır. |
Transport layer |
Tcp-Udp
protocollerininde kapsamı içinde olan katmandır.
Applicationdan gelen datalar burada networkte yolculuğa
çıkmak için hazırlanır. |
Network |
Network
paketler arası haberleşme olarak litaratürde geçmektedir.Ama
genelde ingilizce kavramları terimsel olarak kabul etmek
daha mantıklı bu yüzden frame diyeceğiz. Yani yolculuğa
frameler ile başlıyoruz.Aslında network tam bir yolculuk.
Düşününki bir tren yolculuğuna çıkıcaksınız. Daha önceden
nereye gideceğinizi biliyorsanız, hangi trenle gideceğinizi
de bilirsiniz. İşte bizim yolculuğumuzda gideceğimiz
yer(destination ip), gittiğimiz yol(kablolar), başlangıç
adresimiz(source ip) olarak düşünülebilir. Aslında mantık
düz olarak bu. Eğerki yolda tren raydan çıkmaz, vagonları
patlamaz ise hedefe ulaşabiliriz. Yolda kaza olursa bu
kazalara "collision" denir. Bir kaza olduysa frameler
patlar. |
Data Link |
Bu katmanda ip
header’lar ve frame trailer denilen yapılar transport
layerde ayrılan framelere eklenir. |
Physical |
Tamamen
bitlerin iletildiği kablolar ve sinyallerin dolu olduğu
katmandır. |
Haberleşmenin Sağlanması:
Haberleşme sürekli olarak birbirine haber gönderme mantıyla çalışır. Yani bir
akarsu yapısının bire bir aynısıdır diyebiliriz. Bir akarsu sürekli akar.
İnsanların çok olduğu yerde akarsunun şiddeti azalır az olduğu yerde ise hızı
artar. Gelelim konumuza; bizim akarsuyumuzda frameler sürekli akar. Yani sürekli
akan bu akarsuda bazı bilgileri balık gibi tutmak istersek akarsuyun tamamına
bir ağ koyarak bu balıkları tutabiliriz. Yani bir server uygulaması paketleri
sonsuz ve bitmeyen bir döngü içinde dinleyecektir. Paketi gönderecek client’ ın
ise böyle bir şeye ihtiyacı yoktur. Sonuçta client akarsuya bir kere frame
bırakıyor o kadar. En az boyutlu, yani data içermeyen frame boyutu 64 byte’dır.
Dolayısıyla data yüklendikçe akarsu yoğunluğu artacak ve server biraz
yavaşlayacaktır.
.Net’te network için kullanacağımız isim
alanları ve class’lar:
Kullanacağımız isim alanları
System.Net, System.Net.Sockets isim alanlarıdır. Bu ikisinin tüm
nesneleri networkle ilgilidir. Diğer kullanacağımız isim alanları
ise; System.Threading, System.Text isim alanları. Dilerseniz Network
programımıza geçelim. Bir server ve bir client olduğunu düşünelim.
Client mesaj yollayınca server bu mesajı aldığını karşı tarafada
yollasın. Yani bir nevi chat. Bunun için işe server’dan başlayalım.
server.cs:
Server baştada söylediğimiz gibi
sürekli dinleme durumunda olacak. Bu yüzden bu işi sonsuz bir döngü ile
hallederiz ama sonsuz döngü çalışınca uygulamamızın kilitlenmesine yol
açabilir. Bu yüzden sonsuz döngü olan metotu kanallamalıyız. Bu
kanallamayı threading namespace’i ile yapalım. Bu kanallama işeminin
uygulama başlar başlamaz olması en mantıklısı. Bu yüzden bu işlemi
Formun constructor’ında gerçekleştireceğiz.
System.Threading
using System.Threading;
public Form1()
{
InitializeComponent();
Thread kanal=new Thread(new ThreadStart(dinle));
try
{
kanal.Start();
kanal.Priority=ThreadPriority.Highest;
MessageBox.Show("Server
açıldı");
}
catch(ThreadAbortException hata)
{
kanal.Abort();
MessageBox.Show("Bekleyen
paket yok");
}
} |
Yeni bir kanal oluşturduktan sonra bu kanalı
try-catch ile kırılmayı önlemek için kontrol etmek gerekiyor. Kanal.Priority
bizim kanala verdiğimiz önceliktir. Kanal oluşturulurken, Thread class’ı ile
yeni bir nesne yaratılırak dinlemeye alınıyor. Tabiki bizim dinle adlı void
metotumuz sonsuz döngü........
Not:Threading işlemiyle daha önce ilgilenmeyen ve
mantığını tam kavramayanlar Msdn’den yada daha önce sitede yayınlanan threading
ile ilgili makalelere bakarak bilgilerini geliştirebilirler ki, geliştirmekte
olduğumuz network uygulamalarının anlaşılması açısından bu kavramların iyi
öğrenilmesi gereklidir..
System.Text:
using System.Text; // bu namespace ile
text işlemlerini kolayca gerçekleştirebiliriz.Yazıyı byte dizisine,diziyi
yazıya çeviren bir yapı.
byte[]dizi=Encoding.ASCII.GetBytes("CANER");//Kelimelerin ascii kodlamadaki
byte değerlerine alarak diziye yerleştirir.terside geçerlidir
string veri=Encoding.ASCII.GetString(dizi);.//Aynı şekilde byte diziside
string veriye çevrilebilir. |
System.Net.Sockets:Bu isim alanında
bulunan bir çok class ise bizim esas işlerimizi yapan metotları barındırıyor. Bu
kavramlara server’ı dinleme işlemini yapan TcpListener ile başlayalım.
TcpListener dinleyici=new
TcpListener(port);
dinleyici.Start(); |
Yeri gelmişken port kavramını da açıklayalım.
Portlar işletim sitemi, uygulamaların ve protocollerin ortak kullandıkları çıkış
birimleridir. port sayısı 65000 civarındadır. 1023’e kadar olan portlar bilinen
portlardır. Yani belirli protocoller için hizmet verirler. Örneğim http:(yani
web) 80.porttan, ftp:21’den,telnet 23’den vs. Bunlar dünyada standart olarak
kabul edilmiş numaralardır. Buradan şu çıkarki; iki bilgisayar konuşacaksa aynı
port numarasını kullanmalıdır. Ben uygulamada 10000 numaralı portu bizim
uygulamamız için ayırdım. Eğer bir firewall bilgisayarınızda kurulu ise bu
portları kapamış olabilir. Bu yüzden firewall’dan 10000 numaralı portu açmasını
ayarlayın yada firewall’u geçici olarak kapayın.
const int port=10000;
private void dinle()
{
string cevap="Mesajiniz basariyla
alinmistir.";
string ip;
string gelen;
TcpListener dinleyici=new
TcpListener(port);
byte[]gelenveri_dizi=new byte[1024];
byte[]gonderveri_dizi=Encoding.ASCII.GetBytes(cevap);
while(true)
{
dinleyici.Start();
Socket
soket=dinleyici.AcceptSocket();
soket.Receive(gelenveri_dizi,gelenveri_dizi.Length,0);
gelen=Encoding.ASCII.GetString(gelenveri_dizi);
listBox1.Items.Add(gelen);
ip=soket.RemoteEndPoint.ToString();
listBox2.Items.Add(ip);
soket.Send(gonderveri_dizi,gonderveri_dizi.Length,0);
label4.Text=listBox1.Items.Count.ToString();
dinleyici.Stop();
}
} |
Görüldüğü gibi
yukarıdaki örnekte sonsuz döngü ile 10000 numaralı port
dinleniyor. Böylece bütün işlemler byte dizileri ile
olucağı için Text kütüphanesinin metotları kullanılarak
kolay biçimde dönüşüm sağlanıyor. Fakat bu dönüşümde
Ascii karakterlerini kodladığımız için Türkçe
karakterler doğal olarak çıkmayacak ve anlamsız
karekterler oluşacaktır. İşte soket sınıfı tam anlamıyla
TcpListener’ın türetildiği bir classtır ve bu class ile
istenilen protocol’den soket oluşturulabiliriz. Biz
burda dinlenen veriyi soket nesnesine bağlayarak soket
ile networke veri yollama ve networkten veri okumayı
yapabiliyoruz.TcpListener ise adındanda anlaşıldığı gibi
portu dinlemeye alıyor. Burada bir dinleyip sonra
porttan dinlemeyi kesiyoruz, fakat sonsuz defa bu işlemi
gerçekleştirmemiz veri akışını sağlamış oluyor.
Ayrıca buttonlarlada threading kanalını askıya
alarak verilerin sıra ile portta yığılması ve beklemesi sağlanıyor. Resume ile
bu porttan veri akışı tekrar sağlanıyor. Thread’i askıya almak bizim sonsuz
döngümüzün çalışmadığı anlamına gelmez. Sadece thread’e bir ara veriyor ve
veriler bir kuyruk oluşturuyor.
client.cs
Gelelim client kısmına. Bu Kısımda
kullanacağımız 2 tane class varki bunlar; TcpClient ve NetworkStream classları .
Tcpclient:
TcpClient tam anlamıyla client için
tasarlanmış bir yapıdır ve client’ın nereye veri göndereceği, nereye
bağlanacağı, verileri nasıl paketleyeceği, nasıl ileteceğini belirlemede
kullanılır.
TcpClient gonder=new TcpClient(ip,port);
NetworkStream okuryazar=gonder.GetStream();
string mesaj=textBox1.Text;
byte[]mesaj_dizi=Encoding.ASCII.GetBytes(mesaj);
byte[]gelen=new
byte[gonder.ReceiveBufferSize]; |
gonder isimli TcpClient nesnesi oluşturularak
clientımız hazır duruma geçiyor ve böylece servera baglanıyor. Daha sonra ise
Tcpclient nesnesinin metodlarından olan GetStream() ile bu baglantı
NetworkStream nesne’sine atanıyor. NetworkStream nesnesi ise paketleme
işlemimizi yapan nesne durumundadır. Dikkat ettiyseniz gonderilen mesaj byte
dizisine çevrilmiştir. Aynı şekilde gelen verilerde ReceviBufferSize özelliğinin
döndüğü değer olan gelen veri boyutu kadar bir dizi yaratılıyor. Artık sadece
Yazma işlemimi Okuma işlemimi yapıyoruz buna karar vermemiz gerekiyor. Bunlar
ise NetworkStream sınıfının ve üyelerinin işi.
NetworkStream:
NetworkStream class’ı bir stream classı’dır. Eğer
daha önce dosyalama ile uğraştıysanız StreamWriter, StreamReader’ı hatırlarsanız
ki mantık aynıdır. Sonuçta veri akışı bu Streamler ile yapılır.
if(okuryazar.CanWrite)
{
okuryazar.Write(mesaj_dizi,0,mesaj_dizi.Length);
}
else
{
gonder.Close();
return;
}
if(okuryazar.CanRead)
{
okuryazar.Read(gelen,0,(int)gonder.ReceiveBufferSize);
string
gelenveri=Encoding.ASCII.GetString(gelen);
listBox1.Items.Add(gelenveri);
}
else
{
gonder.Close();
return;
} |
Burada networkstream nesnesi olan okuryazar
class’ından CanRead ve CanWrite ile bool bir veri tipi döner. Eğer okuma varsa
karşı taraf bize veri yolluyor anlamındadır. Biz bunu okuryazar nesnesinin read
metotuyla bir byte dizisi içine alarak veriyi elde ederiz. Eğer yazma durumu
varsa göndereceğimiz veriyi bir byte dizi içine alarak bu diziyi okuryazar
nesnesinin Write() metotu ile yazarız. Eğer bu durumlar kabul edilmezse yani bir
okuma-yazma durumu permit konumu doğru değilse Stream kapanarak else bloğundan
çıkılarak kaldığı yerden devam eder. Birde okumamı önce yapılacak,yoksa yazmamı
yapılacak burası önemlidir. Eğer okumayı önce yaparsak ilk başta servera gelen
veri olmadığı için sonsuz döngüde takılıp kalacaktır. Bu yüzden ilk önce veriyi
yazalımki cevabı alalım böylece bu sorun giderilir.
Anlatımlar ile ilgili eleştirilerinizi belirtmeniz
herkes için yararlı olacak ve hatalarımızı görmemize yardımcı olacaktır. C# ile
Network programlama-3 yazısında görüşmek dileğiyle..
NOT : İp adresini 127.0.0.1 yapmamızın
sebebi loopback ile kendi bilgisayarımız üzerinde bir network gibi çalışmamızı
sağlamasıdır. Bu ip adresini değiştirerek bilinen bir ip adresinden sizin
servera internet’ten mesaj gönderilmesini sağlayabilirsiniz. Bununla birlikte
server’ı ilk açtığınızda bir hata alacaksınız. Bu hatanın sebebi o anda bağlanan
makina olmaması ve veri gelmemesidir. Devam ederseniz, clientlar masaj
yolladıkça bu hata çözülecektir. Eğer internetle işim olmaz diyorsanız TcpClient
nesnesi yerine UdpClient nesnesini kullanmanızı öneririm. TcpClient ile çalışma
mantığı metotları benzer.
Kaynak
kodlar için tıklayın.
CANER ŞAHAN
[email protected]
Makale:
C# ile Network Programlama-2 C#, Visual C# ve .NET Caner Şahan
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|