Makale Özeti

C# ile dosya erişiminin ardından, network erişimi üzerine bir yazı ile devam ediyoruz.

Makale


Socket Programlama (Network I/O) -1-
Giriş
Konu hakkında söylenecek ilk söz network üzerinden bilgi alışverişinin yerel diskinizden dosya okuma işleminden pek farklı olmadığı olacaktır. Dosya işlemlerindeki gibi Stream’leri ve ayrıca soketleri kullanacağız. Bu sebeple dosya işlemleri yazılarına tekrar göz atmanızda fayda var.
Network programlama birden fazla proses veya programın farklı bilgisayarlar üzerinde birbirleriyle haberleşerek çalıştırılması olarak tanımlanabilir. Bu yazımızda network programlamanın C# ile nasıl yapılacağını göreceğiz. Ağ programlamada iki farklı protokol kullanılır. TCP ve UDP. Öncelikle bunların ne olduğunu açıklığa kavuşturalım. TCP connection oriented bir protokoldür. Yani iki bilgisayar arasında önce bir bağlantı gerçekleştirilir daha sonra bu bağlantı kullanılarak haberleşme işlemi yapılır. Örneğin telefonla bir arkadaşınızla görüşmek istemeniz gibi. Önce aranızda bir bağlantı kurulur daha sonra bu bağlantıyı kullanarak birbirinizle konuşursunuz. UDP ise connection-less oriented protokoldür. Bununda arkadaşınıza mektup göndererek haberleşme isteğinde bulanmak şeklinde açıklayabiliriz. Bu konu ile daha detaylı bilgiyi “Computer networks and Internets, Prentice Hall” kitabından yada bu kitaba ait web sayfasından www.netbook.cs.purdue.edu alabilirsiniz. (not ana sayfadan ulaşamayacağınız eğitmen notları adresi: www.purdue.netbook.cs.purdue.edu/cs363).
Karşılaştırmaları:
1-      UDP daha hızlı
2-      UDP’de paketler kaybolabilir ve veriler istenen sırada gitmeyebilir
3-      UDP daha az network trafiğine neden olur.
Port ve Soket kavramı
Bir bilgisayar ağa sadece tek bir bağlantıyı kullanarak ulaşır. Eğer tüm veriler bu bağlantıyı kullanarak veriyi gönderecekse bilgisayar üzerinde çalışan uygulamalar hangi verinin kendilerine ait olduğunu nasıl anlayacak? İşte bu sorunun cevabı port kavramında yatıyor.
Bir bilgisayar üzerinde çalışan uygulamaların netten gelen verilerin hangilerinin kendilerine ait olduğunu tespit etmeleri için port dediğimiz bir çeşit kimlik numaraları kullanırlar. 65535 tane port vardır (16 bit). Fakat bunların tamamının kullanımı bize bırakılmamıştır. Bazıları tahsis edilmiştir. (örneği 21 FTP portudur, 80 HTTP gibi …)
Soket, net üzerinde çalışan iki prosesin haberleşmesi için, port ve ip adresinin birleşiminden oluşturulmuş bir nesnedir. Soket, hem TCP hem de UDP protokollerini kullanarak yapılan haberleşmede kullanılabilir. Biz ilk önce TCP’yi kullanarak bir takım örnekler geliştireceğiz. (Not: Soket oluştururken farklı iki makine IP adresini kullanarak haberleşme sağlayabileceğiniz gibi iki proses için aynı makine IP adresini kullanarak ta, aynı bilgisayar üzerinde çalışan iki farklı programın haberleşmesini de sağlayabilirsiniz.)
Server soketi oluşturur ve verilen bir portu dinlemesi söylenir. Socket kurucusu bir int parametresi alır. Bu dinlenecek olan port numarası olur. Socketi oluşturduktan sonra Start() metodunu çağırarak socketin dinlemeye başlamasını sağlarsınız. Server artık bağlantı kabul etmeye hazır hale geldikten sonra Accept() metoduyla bağlantıyı kabul edersiniz. Telefonun başında sizin aramanızı bekleyen birini düşünün. Siz aradıktan sonra arkadaşınız telefonu kaldıracak ve sizden sonra arayanlar bir müzik sesi dinleyerek bağlantı kuramayacaklardır. Fakat ileride aynı anda nasıl binlerce bağlantı kabul edebileceğimizide göreceğiz. Şimdilik şöyle düşünün gelen bir bağlantı için yeni bir soket oluştururuz ve diğer soketimiz yeni bağlantı beklemeye başlar!… Hemen küçük örneklerle konuya giriş yapalım.
Network Server oluşturmak
TCP protokolünü kullanan bir server oluşturmak için öncelikle verilen portu dinleyip bir istek geldiğinde soketi oluşturacak yapı kurmamız lazım. İşte server cephesinde verilen bir portu dinleyecek olan nesne bir TcpListener nesnesidir. Bu nesneyi oluştururken bir integer sayıyı kurucuya parametre olarak verip hangi portu dinlemesi gerektiğini ifade edeceğiz. Biz 65000 nolu portu kullanalım.
TcpListener tcpListener = new TcpListener(65000)
Portu dinleyecek nesneyi oluşturduktan sonra dinlemeye başlamasını sağlamalıyız.
tcpListener.Start();
Şimdi Client tarafından bir isteğin gelmesini bekleyeceğiz ve istek olunca soketi oluşturacağız
Socket istemciIcinSocket=tcpListener.Accept();
Program bu noktada, bir istek gelene kadar bloklanacaktır.
Artık soket bağlantımız yapıldıysa veri göndermeye başlayabiliriz.
İf(istemciIcinSocket.Connected)
{
dosya işlemlerinde yaptığımız gibi artık sıra streamleri kullanmaya geldi. Burada NetworkStream kullanacağız. socket nesnesini kurucuya parametre olarak gönderip stream oluşturulur.
NetworkStream networkStream = new NetworkStream(istemciIcinSocket);
Daha öncede yaptığımız gibi şimdi streamwriter oluşturacağız tek farkı bu dosyaya değil networke yazacak.
System.IO.StreamWriter streamWriter= new System.IO.StreamWriter(networkStream);
Artık server veriyi clienta yazacak yapıya kavuştu. Aşağıdaki, en temel yapıyı kullanılarak yukarıdaki yapıyı esas alan örnek programı inceleyiniz.
using System;
using System.Net.Sockets;
namespace princeNET
{
 class NetworkIOServer
 {
  static void Main(string[] args)
  {
  NetworkIOServer app = new NetworkIOServer();
  app.Run();
  }
  private void Run()
  {
  //bir tcplistener oluştur
  //65000 nolu protu dinle
  TcpListener tcpListener = new TcpListener(65000);
  tcpListener.Start();
  //şimdi istek olana kadar portu dinle
  for(;;)
  {
  //eğer istek olursa bağlantıyı kabul et
  //bir soket oluştur
  Socket istemciIcinSocket = tcpListener.AcceptSocket();
  if(istemciIcinSocket.Connected)
  {
  Console.WriteLine("istemci bağlandı...");
  //dosyayı gönderecek metodu çağır
  istemciyeDosyaGonder(istemciIcinSocket);
  Console.WriteLine("Bağlantı Kapatılıyor...");
  istemciIcinSocket.Close();
  Console.WriteLine("Programdan Çıkılıyor");
  break;
  }
  }
  }
  //dosyayı gönderecek metot
  private void istemciyeDosyaGonder(Socket istemciIcinSocket)
  {
  //networkstream ve streamwriter oluştur
  NetworkStream networkStream = new NetworkStream(istemciIcinSocket);
  System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
  //dosyayı okuyacak streamreader oluştur
  //önceki yazıda açıklandığı gibi
  System.IO.StreamReader streamReader = new System.IO.StreamReader(@"c:\deneme\source\prince.txt");
  string satir;
  //okunan veri boyu sıfırdan büyük oldukça veri oku
  //veriyi istemciye gönder
  do
  {
  satir=streamReader.ReadLine();
  if(satir!=null)
  {
  Console.WriteLine("Gönderiliyor {0}",satir);
  streamWriter.WriteLine(satir);
  streamWriter.Flush();
  }
  }
  while(satir!=null);
  streamReader.Close();
  networkStream.Close();
  streamWriter.Close();
  }
 }
}
Bu servera bağlanacak birde client yazarsak programı deneme fırsatı bulabileceğiz. (not her program için client olarak telneti kullanabilirsiniz: telnet ip port yani, c:\>telnet localhost 65000 gibi… her program için telneti client olarak kullanabilirsiniz. ftp’yi bu yolla denemenizi öneririm. ftp 21 nolu port. Bir server için 13 nolu portuda deneyin.)
Network Client oluşturmak
Client, TcpClient sınıfını kullanarak verilen bir IP’ye verilen bir porttan bağlanmaya çalışır.
TcpClient serveraBaglantiSocketi;
serveraBaglantiSocekti = new TcpClient(“localhost”,65000);
bu TcpClient’ı kullanarak bir networkStream oluşturduktan sonra veriyi okuyacağınız StreamReader’ı oluşturabilirsiniz.
NetworkStream networkStream = serveraBaglantiSocketi.GetStream();
System.IO.StreanReader streamReader = new System.IO.StreamReader(networkStream);
Şimdi streamda veri oldukça onu okuyabilir ve veriyi consola yazabilirsiniz.
do{
gelenstring=streamReader.ReadLine();
if(gelenstring!=null)
{
 Console.WriteLine(gelenstring);
}
}while(gelenstring!=null);
Şimdi client programının tüm koduna bakalım.
using System;
using System.Net.Sockets;
namespace princeNET
{
 class Client
 {
  static void Main(string[] args)
  {
  //servera bağlanacak tcpclient oluştur
  TcpClient serveraBaglantiSocketi;
  try
  {
  serveraBaglantiSocketi=new TcpClient("localhost",65000);
  }
  catch
  {
  Console.WriteLine("Bağlantı başarısız oldu");
  return;
  }
  //networkstream ve streamreader oluştur
  NetworkStream networkStream=serveraBaglantiSocketi.GetStream();
  System.IO.StreamReader streamReader=new System.IO.StreamReader(networkStream);
  try
  {
  string gelenstring;
  //veriyi oku ve ekrana yaz
  do
  {
  gelenstring=streamReader.ReadLine();
  if(gelenstring!=null)
  {
  Console.WriteLine(gelenstring);
  }
  }
  while(gelenstring!=null);
  }
  catch
  {
  Console.WriteLine("serverdan veri okunurken hata oluştu");
  }
  networkStream.Close();
  }
 }
}
önce server programını çalıştırın. İlgili path’teki dosyayı oluşturun. Sonra clientı çalıştırın. İyi eğlenceler. Bir sonraki yazı aynı anda bir çok bağlantı kabul etme ve asenkron network iletişim konularını göreceğiz. Görüşmek dileğiyle.
Referans:
Programming c#