Makale Özeti

C# ile network işlemlerine devam ediyoruz

Makale

Socket Programlama (Network I/O) -2-

Bir önceki yazıda bir server ve client yazdık. Bu program sadece tek bir bağlantı kabul edebiliyordu. Fakat bir server aynı anda binlerce bağlantı kabul edebilir. Bu yazımızda öncelikle aynı anda bir çok bağlantıyı kabul etmeyi göreceğiz. Bununla birlikte c#ile dosya işlemleri konusunda olduğu gibi network üzerinden veri aktarımını asenkron olarak nasıl yapacağımız üzerinde duracağız.

Aynı anda bir çok bağlantıyı kabul etme

Aynı anda bir çok bağlantıyı kabul edecek bir sınıfın yönetimi; gelen bağlantıya soket oluşturacak yeni bir sınıf oluşturup, bir bağlantı isteği geldiğinde bağlantıyı bu sınıfın kurucusuna paramatre olarak gönderip bu sınıfın soket oluşturmasını sağlayacağız.

Bu yeni sınıf ClientHandler olsun. Bu sınıfın kurucusu, soketin bir kopyasını, yeni bir buffer ve bir networkstream oluşturur. Bu işlem gelen her istek için gerçeklenir. Aynı zamanda dosya aktarımını asenkron olarak gerçekleştirmek için iki delegate metodu tanımlar, okumabittiginde ve yazmabittiginde.

Yapacağımız programdaki Run metodu bir önceki yazıdaki Run metodundan pek farklı değil. İlk önce bir listener oluşturur. Ardından onu başlatır. (Start()) daha sonra bir sonsuz döngüye girip AcceptSocket() ile gelen bağlantıları kabul eder. Oluşturulan bu socketi ClientHandler sınıfına paramatre olarak geçirip yeni bir kopya soket oluşturur. ClientHandler Oku() metodunu çağırarak okuma işlemini başlatır.

İşin teorik kısmı bu kadar basit, konunun örnek program üzerinde daha iyi anlaşılacağı düşüncesindeyim. Aşağıdaki programı inceleyiniz.

using System;

using System.Net.Sockets;

namespace princeNET

{

 class AsenkronNetworkServer

 {

  class ClientHandler

  {

  public ClientHandler(Socket istemciIcinSocket)

  {

  //socketin kopyasını, yeni bir buffer ve network stream oluştur

  socket=istemciIcinSocket;

  buffer=new byte[32];

  networkStream = new NetworkStream(istemciIcinSocket);

  callBackRead=new AsyncCallback(this.okumabittiginde);

  callBackWrite= new AsyncCallback(this.yazmabittiginde);

  }

  //clienttan strin okumaya başla

  public void oku()

  {

  //ilk okuma işini gerçekleştirir sonra callBackreadle ilişkilendirilmiş metodu çağırır

  networkStream.BeginRead(buffer,0,buffer.Length,callBackRead,null);

  }

  //okuma işi bittiğinde stringi ekrana yaz daha sonra kontrolu tekrar kullanıcıya bırak

  private void okumabittiginde(IAsyncResult ar)

  {

  //kaç byte okunmuş

  int okunanByte=networkStream.EndRead(ar);

  if (okunanByte>0)

  {

  string s=System.Text.Encoding.ASCII.GetString(buffer,0,okunanByte);

  Console.WriteLine(s);

  //aldığın texti tekrar clienta gönder. gönderme işi bitince callBackwrite ile ilişkili metodu çağır.

  networkStream.BeginWrite(buffer,0,buffer.Length,callBackWrite,null);

  }

  else

  {

  Console.WriteLine("Herhangi bir string okunmadı bağlantı kapatılıyor");

  networkStream.Close();

  socket.Close();

  networkStream=null;

  socket=null;

  }

  }

  //yazma işi bitince çalıştırılacak metot

  private void yazmabittiginde(IAsyncResult ar)

  {

  networkStream.EndWrite(ar);

  Console.WriteLine("Text gönderme işi bitti");

  //tekrar oku...

  networkStream.BeginRead(buffer,0,buffer.Length,callBackRead,null);

  }

  private byte[] buffer;

  private Socket socket;

  private NetworkStream networkStream;

  private AsyncCallback callBackRead;

  private AsyncCallback callBackWrite;

  }

  static void Main()

  {

  AsenkronNetworkServer asenkronserver = new AsenkronNetworkServer();

  asenkronserver.Run();

  }

  private void Run()

  {

  //yeni bir TcpListener oluştur ve dinlemeye başla port:65000

  TcpListener tcpListener = new TcpListener(65000);

  tcpListener.Start();

  //birçok bağlantıyı kabul etmek için sonsuz döngü

  //gelen her istek için oluşan soketi ClientHandlera gönder yeni bir soket oluştursun.

  for(;;)

  {

  //istek olursa kabul et ve istemciIcinSocket isminde yeni bir soket oluştur

  Socket istemciIcinSocket = tcpListener.AcceptSocket();

  if(istemciIcinSocket.Connected)

  {

  Console.WriteLine("Client Bağlandı");

  ClientHandler handler = new ClientHandler(istemciIcinSocket);

  handler.oku();

  }

  }

  }

 }

}

Şimdide bu servera bağlanacak bir client yazalım. (not: Client olarak telneti kullanmayı deneyin önce… Telnet localhost 65000 bu kadar…)

using System;

using System.Net.Sockets;

using System.Runtime.Serialization.Formatters.Binary;

using System.Threading;

namespace princeNET

{

 class AsenkronClient

 {

  static int Main(string[] args)

  {

  AsenkronClient asenkronClient = new AsenkronClient();

  return asenkronClient.Run();

  }

  AsenkronClient()

  {

  string serverismi="localhost";

  TcpClient tcpClient = new TcpClient(serverismi,65000);

  serveraStream = tcpClient.GetStream();

  }

  private int Run()

  {

  string mesaj = "Asenkron servera Merhaba";

  //bir streamwrter oluştur

  System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(serveraStream);

  streamWriter.WriteLine(mesaj);

  streamWriter.Flush();

  for(double i=1;i<3000000;i++)

  {

  }

  //cevabı Oku

  System.IO.StreamReader streamReader = new System.IO.StreamReader(serveraStream);

  string cevap=streamReader.ReadLine();

  Console.WriteLine(cevap);

  serveraStream.Close();

  return 0;

  }

  private NetworkStream serveraStream;

 }

}

Uygulama yapmanız için biraz ödeve ne dersiniz J

Asenkron dosya işlemleri ve asenkron network işlemleri üzerine gerekli konuları işledik. Bu ikisini kullanarak yapmanız gereken bir alıştırma. Network üzerinden asnekron dosya gönderimi işlemini yapacak bir program geliştiriniz.

Yapı şöyle olmalı:

MyFileCallBack=new AsyncCallback (this.dosyaokumabittiginde);

callBackRead= new AsyncCallback(this.okumaBittiginde);

callBackWrite = new AsyncCallback(this.yazmaBittiginde);

Serverdaki Run metodunuz gelen bağlantıyı kabul edecek (sonsuz döngüde!). Bir ClientHandler sınıfınız yeni bir soket ve gerekli üyeleri oluşturacak. Ve oku() metonunu çalıştırarak yukarıdaki yapıya benzer dosya okuma işlemini başlatacak. Gerekli yerde delegate’leri kullanmalısınız.

Kolay gelsin.

Bir sonraki network yazısı UDP protokolünü kullanarak bir haber servisi oluşturmak hakkında olacak. Server bir haber gönderecek ve tüm clientlar bu haberi alacak. Yeni uygulamalarda görüşmek temennisi ile.

Tuğrul Karakaya

Referans:

Programming c#