Silverlight ile Asenkron Soket Programlama

Batuhan Düzgün tarafından yayınlanmıştır 10. February 2012 08:18

Merhaba arkadaşlar, gece gece bu adam çıldırmışta oturup makale hazırlamış diyebilirsiniz. Aslına bakılırsa kısa bir İstanbul gezintisi yapıp, bu yazının başına oturdum. Sanırım Bilgisayar Mühendisliği’nin verdiği genetiksel bir alışkanlık olsa gerek gece çalışmak. Aslında, daha da lafı uzatmadan bugünkü makale konuma gelmek istiyorum. İlginç bir konu başlığı olan ve bitirme tezimde bir hafta boyunca bana saç baş yolduran Silverlight ile Soket Programlama.  Gerçekten  de, anlatılan makalelerdeki eksik bilgiler ve Türkçe düzgün bir anlatım olmamasından ötürü epey zorlanmıştım.

Silverlight soket programlamada en önemli yapı asenkronluktur. Asenkron callback’ler ile kod satır satır işletilir ve bir olay tetiklendiğinde ilgili satıra dönüş yapılır. Yapacağımız proje aslında server-client haberleşmesine dayalı olacak.

Yapılacak Adımlar

-Delphi Server

-Silverlight Web Client

-PolicyServer

Projede Delphi ile server yazılımı gerçekleştirilecek, bunun yanı sıra Silverlight ile web tarafı hazırlanacak. Projede web arayüzünden bir kullanıcı adı ve şifre gönderilecek ve server buna bir mesaj gönderecek. Basit bir iletişim mantığında kısa bir haberleşme olayı olacaktır.

Silverlight Web Client Geliştirilmesi

Projeye aslında web tarafındaki client yazılımını yazarak başlayalım. Aşağıdaki resimdeki gibi File>>Project>>New yapıp Silverlight projesi açılır. 

 

Yapacağımız projede kullanıcı adını ve şifreyi gireceğimiz kısım aslında burası olacak. Soket işlemleri ile ilgili temel sınıfları bir statik sınıf içerisinde toplayıp, bu veri tiplerine erişimi her noktadan ve tek bir yerden sağlamak  amacım.  Bunun için aşağıdaki gibi projeye yeni bir sınıf eklenir.

 

 

usingSystem;

usingSystem.Net;

usingSystem.Net.Sockets;

 

namespaceSilverlightWebClient

{

    public static class SocketInitProcesser

    {

        // Akış tabanlı TCP protokolünü kullanan bir Socket nesnesi oluşturuyoruz.

        public static Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        // Asenkron bir socket çağrısı geldiğinde tetikleyici rolünü üstlenecek olan sınıf.

        public static SocketAsyncEventArgs AsenkronSocketCaller;

        // Server tarafında hangi IP adresine ve port numarasına bağlı uç birime bağlanılacağının bilgisi tutulur.

        public static DnsEndPoint EndPointForSocket = new DnsEndPoint("127.0.0.1", 4532);

    }

}

 

Projemizde var olan Silverlight sayfalarının C# kod dosyasına aşağıdaki kodları yazıyoruz. Bu kodlar açıklama satırlarıyla birlikte verilmiştir. Hazırlanan kod yapısı, serverdan gelen mesajı yakalamaya yönelik, aynı zamanda server’a veri göndermeyi sağlayacak şekildedir.

 

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Net;

usingSystem.Windows;

usingSystem.Windows.Controls;

usingSystem.Windows.Documents;

usingSystem.Windows.Input;

usingSystem.Windows.Media;

usingSystem.Windows.Media.Animation;

usingSystem.Windows.Shapes;

usingSystem.Net.Sockets;

usingSystem.Text;

 

namespaceSilverlightWebClient

{

    public partial class MainPage : UserControl

    {

        //Bu sınıf yapısında tam olarak işlem girilen kullanıcı adı ve şifreyi uzaktaki serverdan,

        //sorgulayıp eğer ilgili şifre ve kullanıcı adına sahip bir kayıt varsa,

        //GoogleMapHaritasi.xaml sayfasına yönlendirilen bir algoritma söz konusudur.

 

        //Server tarafından gelen veriyi tutacak olan byte dizisi

        private byte[] ServerData;

 

        //Serverdan veri geldiğinde textbloxk nesnesini uyaracak olan ve gelen mesajı,

        //yakalayıp string veri tipine dönüştürcek olan metodu tetikleten delegate .

        public delegate void SetCallBack(string Textim);

 

        //eğer gelen mesaj OKEY ise diğer sayfaya yönlendirme yapılmasını sağlayan delegate.

        public delegate void YonlendirmeYap(string Texffim);

 

        //Gelen mesajı yakalamak için kullanılan değişkenler...

        string UserName;

        string UserPassword;

        string ServerMessage;

 

        public MainPage()

        {

            InitializeComponent();

 

            //Soket işlemlerine dair bütün nesneleri ve yapıları static bir sınıfta  tanımlanır.

            //Çünkü bu sayede ilgili nesnelere geliştirilen kaynak kodun her noktasından erişim sağlanmış olur.

            //Bütün soket işlemlerinde bu static sınıf içinde yer alan nesneler kullanılacaktır.

            //Böylece tek bir soket üzerinden bağlantılar açılıp kapatılacaktır.

 

            //Tcp protokolü kullanan , stream (akış) tabanlı bir soket açılır.

            //SocketIslemler.MySevimliSoketim = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

 

            //Asenkron soket iletişimini sağlayan yapıdır.

            //Asenkron soket uygulamalarında kullanılır.Önemli özelliği, client yazılımın server'ı sürekli sorguladığı ,

            // senkron sistemden kaçınmasıdır.Özellikle bunun web tarafında yapılması sayesinde silverlight soket ortaya çıkmıştır.

 

            //Geçici bir asenkron soket olay yakalayıcı kullanıyoruz.

            SocketAsyncEventArgs MyAsenkronEvent = new SocketAsyncEventArgs();

 

            //RemoteEndPoint ile asenkron soket işlemleri için uç IP noktası belirliyoruz.

            MyAsenkronEvent.RemoteEndPoint = SocketInitProcesser.EndPointForSocket;

 

            //Bağlantı kurulum işlemi tamamlandığında "Baglanti_Tamamlandi" adlı metod otomatik olarak tetiklenecektir.

            MyAsenkronEvent.Completed += new EventHandler(Connection_Completed);

 

            //asenkron işlemler için açtığımız soket asenkron bir şekilde karşı tarafa bağlanmasını sağlar.

            SocketInitProcesser.ClientSocket.ConnectAsync(MyAsenkronEvent);

        }

        public void Connection_Completed(object sender, SocketAsyncEventArgs e) {

            //Global olarak tanımladığımız Asenkron soket olay yakalayıcısına yeni bir bellek alanı tahsis ediyoruz,

            //Yani yeniden oluşturuyoruz.

            SocketInitProcesser.AsenkronSocketCaller = new SocketAsyncEventArgs();

 

            //Belirttiğimiz uç IP adresinde sonlanacak olan RemoteEndPoint özelliği doldurulur.

            SocketInitProcesser.AsenkronSocketCaller.RemoteEndPoint = SocketInitProcesser.EndPointForSocket;

 

            //"Baglanti_Tamamlandi" adlı metod çalıştığı zaman bağlantı kurulumu gerçekleşmiştir.

            //Artık asenkron soket olay yakalayıcı bağlantı kurulumunu takip etmesine gerek yoktur.

            //O halde artık asenkron soket yakalayıcının "Completed" adlı olayında veri gelip gelmediğinin takibi,

            //yapılması daha mantıklı olacaktır.Bu yüzden asenkron soket yakalayıcının "Completed" olayını ,

            // "Veri_Almak" adlı metodumuza bağlıyoruz.Artık asenkron soket yakalayıcı veri geldiğinde "Veri_Almak" adlı metodu tetikleyecektir.

 

            e.Completed -= new EventHandler(Connection_Completed);

            e.Completed += new EventHandler(Get_Data);

 

            //Server yazılımdan gelen mesajları byte koda çevirip tutacağımız dizidir.

            ServerData = new byte[5000];

 

            //SetBuffer metodu veri tamponunu asenkron soket uygulamalarıyla birlikte kullanabilmek içindir.

            e.SetBuffer(ServerData, 0, ServerData.Length);

 

            //Kabul tampon alanı içerisine, bağlı olan soketten gelen veriyi alan metoddur.

            //Veri bu kod satırında karşı taraftan alınır.

            SocketInitProcesser.ClientSocket.ReceiveAsync(e);

        }

        //Bağlantı kurulumu bittikten sonra artık veri gelip gelmediğini dinlemek gerekir.

        //"Baglanti_Tamamlandi" adlı metoddan sonra bu metod çağrılır ve veri yakalama işlemi gerçekleştirilir.

        public void Get_Data(object sender, SocketAsyncEventArgs e)

        {

            //Gelen byet halindeki veri "ServerData" adlı byte dizisi içine, alma tamponundan doldurulmuştu.

            //Bu byte halindeki veriyi encoding yöntemiyle string veri tipine çeviriyoruz.

            ServerMessage = Encoding.UTF8.GetString(ServerData, e.Offset, e.BytesTransferred);

 

            //Karakter katarına dönüştürülmüş bu veriyi "SetText" adlı metod ile ilgili textblock 'un text özelliğine atanır.

            SetText(ServerMessage);

 

            //Artık "Veriyi_Almak" adlı metod içinde sürekli veriyi kabul etme modunda bekleyecektir.

            //Veri alma tamponuna veri yazılırsa bu metod tetiklenecek ve gelen veri textblock içerisinde gösterilir.

            //Zaten asenkron soket yakalayıcının "Completed" metodunu "Veriyi_Almak"adlı metod bağlamıştık.

            SocketInitProcesser.ClientSocket.ReceiveAsync(e);

        }

        //Byte dizisinden string veri tipine çevrilmiş veri Dispatcher ile textbloğu uyararak, onun text özelliğine veri yazılır.

        void SetText(string Data)

        {

            //Önemli yapılardan biri de dispatcher yapısıdır.Bu yapı ile sayfada görsel bileşen bir delegate ile uyarılır.

            this.Dispatcher.BeginInvoke(new SetCallBack(UpdateTextBox), Data);

        }

        void UpdateTextBox(string Datax)

        {

            //Gelen veri ekranda gösterilir.

            txtsonuc.Text = Datax;

            ServerMessage = textBlock1.Text.Trim();

        }

 

        private void button1_Click(object sender, RoutedEventArgs e)

        {

            UserName = txtUserName.Text.Trim();

 

            //Kullanıcı soyadı değişkene atıyoruz.

            UserPassword = txtUserPassword.Text.Trim();

 

            //Server yazılıma paket olarak göndermede işimize yaracak olan List veri tipi.

            List> l = new List>();

 

            //yeni bir dizi segmenti açıp hazırladığımız string paketi byte dizisi şekline çevirip, segmente ekliyoruz.

            l.Add(new ArraySegment(Encoding.UTF8.GetBytes(UserName+UserPassword)));

 

            //Gönderme işlemi kullanılacak olan soketi usertoken olarak veriyoruz.

            SocketInitProcesser.AsenkronSocketCaller.UserToken = SocketInitProcesser.ClientSocket;

 

            //Bağlı olan asenkron olay argümanına bir IP uç noktası ekliyoruz.

            SocketInitProcesser.AsenkronSocketCaller.RemoteEndPoint = SocketInitProcesser.EndPointForSocket;

 

            //Asenkron soket işlemleri halleden "SocketAsyncEventArgs" tipinde nesneye Bufferlist özelliğine veri dizisini ekliyoruz.

            SocketInitProcesser.AsenkronSocketCaller.BufferList = l;

 

            //Hazırladığımız verileri asenkron şekilde gönderiyoruz.

            SocketInitProcesser.ClientSocket.SendAsync(SocketInitProcesser.AsenkronSocketCaller);

        }

    }

}

Web tarafında işlemlerimizi tamamlandı. Şimdi de Delphi ile server yazılımı gerçekleştirilmesi aşamasındayım. Bu kısımda Delphi ile küçük bir server yazılım gerçelşetirdim. Bu yazılımda bağlanan kullanıcının adresi listeye ekleniyor. Ardından gelen mesaja “Merhaba” başlığı eklenip karşı tarafa gönderilir.

Aşağıda kaynak kodlar verilmiştir.

unit makalesl;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, ScktComp, MysServerSocket;

type

  TForm1 = class(TForm)

    Label1: TLabel;

    Label2: TLabel;

    ListBox1: TListBox;

    ServerSocket1: TServerSocket;

    MysServerSocket1: TMysServerSocket;

    Edit1: TEdit;

    procedure MysServerSocket1ClientConnect(Sender: TObject;

      Socket: TCustomWinSocket);

    procedure MysServerSocket1ClientRead(Sender: TObject;

      Socket: TCustomWinSocket);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

var

  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.MysServerSocket1ClientConnect(Sender: TObject;

  Socket: TCustomWinSocket);

var

String: Sonuc;

begin

//Soket üzerinden server yazılımın dinlediği porta bağlanan kullanıcı varsa,

//Listbox'a eklenir.

    ListBox1.Items.Add(Socket.RemoteAddress);

end;

procedure TForm1.MysServerSocket1ClientRead(Sender: TObject;

  Socket: TCustomWinSocket);

begin

//Soket bağlantısı sırasında okuma işleminin yapıldığı metoddur.

//Socket.ReceiveText ile gelen mesajı alınır.

//Ardından SendText metoduyla gönderilir.

  Sonuc:=Socket.ReceiveText;

  Edit1.Text:='Merhaba'+Sonuc;

  Socket.SendText(Edit1.Text);

end;

end.

 

Projemizin iki parçasını tamamladım. Şimdi sırada en önemli kısımlardan birine gelindi.  Bu detay yüzünden epey bir zorlanmıştım. Silverlight soket uygulamalarında network güvenliğini bir parça olsun daha da arttırmak için, PolicyServer denen ara bir yazılımın yazılması gerekiyor. İşte bu PolicyServer’ın yaptığı işlem Silverlight Web Uygulamasından gelen asenkron soket isteğini alıp, daha sonra bu Web client uygulamasına özel bir Xml mesajı gönderip. Senin bir Silverlight soket uygulaması olduğunu gördüm, seni gerçek Server yazılıma yönlendirilmene izin veriyorum prensibiyle çalışır. Silverlight soket uygulamasındaki her istek mutlaka PolicyServer onayından geçmelidir. Bunun dışında gerçek Server yazılıma bağlanma durumu söz konusu olamaz. Şimdi PolicyServer yazılımını aşağıdaki gibi kodlayalım.

Xml dosyası aşağıdaki gibidir.

Bu dosyada 4532 nolu portu kullanıma açar ve buradan gelen istekleri kabul eder. Daha sonra bu Xml dosya byte halinde karşı tarafa uç birime cevap olarak gönderilir. Bu Xml formatını alan uç birim kendisine gerçek Server yazılıma bağlanma izninin geldiğini anlar.

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Net;

usingSystem.Net.Sockets;

usingSystem.IO;

 

namespacePolicyServer

{

    class Program

    {

        static void Main(string[] args)

        {

            //Xml dosyanın okunacağı yolu girip, byte dizi haline getiriyoruz.

            //Neden Xml byte haline gönderiyoruz sorusunun cevabı çok basit.

            //Kullanacağımız protokol Tcp , Bu nedenle Tcp sadece byte tabanlı veri iletimini destekler.

            //O yüzden göndrilecek verileri byte'a çevirmemiz gereklidir.

            byte[] FilesForPolicy = File.ReadAllBytes(@"E:Documents and SettingsaractakipDesktopMYSis_ProjectsPolicyServerPolicyServerpolicy.xml");

 

            Socket MyCuteSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

 

            MyCuteSocket.Bind(new IPEndPoint(IPAddress.Any,943));

 

            MyCuteSocket.Listen(5);

 

            byte[] BufferDizi = new byte[1024];

            //Ana döngüde gelen istekleri sürekli bekliyoruz.

            while (true)

            {

                Console.WriteLine("Policy Server Acildi!,Herhangi bir kullanicinin baglanmasini bekliyor!");

                //Gelen kullanıcı bağlantı isteğinin alındığı kod satırı.

                Socket SocketOfme = MyCuteSocket.Accept();

 

                SocketOfme.Receive(BufferDizi);

                //Send işlemi ile yollama işlemi gerçekleştirilir.

                SocketOfme.Send(FilesForPolicy,0,FilesForPolicy.Length,SocketFlags.None);

 

                SocketOfme.Close();

            }

        }

    }

}

 

İletişim için bütün sistem hazır halde. Aşağıdaki sıralamadaki şekilde , sırayla uygulamalar çalıştırılır.

1-) PolicyServer yazılımı

2-)Delphi Server yazılımı

3-)Silverlight web yazılımı

 

Sonuç aşağıdaki gibidir.

 

 

 

 

 

Bir makalemin daha sonuna geldik. Bir sonraki makalemde görüşmek dileğiyle ...

 

Batuhan Düzgün

Bilgisayar Mühendisi

Endüstri Mühendisi

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Etiketler:

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading





Bu site BlogEngine.NET 1.4.5.0 ile oluşturulmuştur. Türkçe çevirisi BlogEngine TR ekibi tarafından yapılmıştır.

Batuhan Düzgün

Sakarya Üniversitesi 

Bilgisayar Mühendisi

Endüstri Mühendisi

Yeditepe Üniversitesi

Bilgisayar Mühendisliği Yüksek Lisans 

 sahibinden.com

   Kıdemli Uzman Yazılım Mühendisi  

E-Mail 

   batuhan.duzgun@sahibinden.com

   batuhan.duzgun@windowslive.com

  github.com/batux

 

Sayfalar

Calendar

<<  September 2019  >>
MoTuWeThFrSaSu
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

Yazıları geniş takvimde göster