NET Remoting' i Kavramak - 2

Değerli Okurlarım, Merhabalar.  

Bu makalemizde, daha önceden değinmiş olduğumuz .net remoting ile ilgili olarak çok basit bir örnek geliştirmeye çalışacağız. Remoting' de amaç, istemcilerin uzak nesnelere ait üyelere erişebilmelerini ve kullanabilmelerini sağlamaktır. Dolayısıyla, remoting sistemi söz konusu olduğunda, remote object, server channels ve client channels kavramları önem kazanır. Olaya bu açıdan baktığımızda ilk olarak bir remote object (uzak nesne) geliştirmemiz gerektiği ortadadır. Daha sonra, bu nesneyi kullanmak isteyecek istemcileri dinleyecek bir server programını yazmamız gerekir. Bu server programı aslında, remote object' i barındıran (host) bir hizmet programı olacaktır. İstemcilerin tek yapması gereken uzak nesneye ait bir örneği, çalıştıkları sistemde kullanarak bir proxy nesnesi oluşturmak ve bu nesne üzerinden server programa istekte bulunarak ilgili uzak nesneye ait metodları çalıştırmaktır. İşte bu noktada server ve client uygulamalardaki channel nesneleri önem kazanır.

Biz bugünkü örneğimizde, TCP protokolü üzerinden haberleşen bir remoting uygulaması geliştirmeye çalışacağız. Öncelikle işe, remote object (uzak nesne) sınıfını tasarlayarak başlayalım. Konuyu daha net anlayabilmek için, uygulamalarımızı editoründe geliştireceğiz. Şimdi aşağıdaki kodlardan oluşan, UzakNesne.cs kod dosyasını oluşturalım.

using System;
using System.Data;
using System.Data.SqlClient;

namespace UzakNesne
{
    public class Musteriler:System.MarshalByRefObject
    {
        public string MusteriBul(string CustID)
        {
SqlConnection con=new SqlConnection("data source=localhost;initial 
catalog=Northwind;integrated security=SSPI");
SqlCommand cmd=new SqlCommand("SELECT * FROM Customers WHERE 
CustomerID='"+CustID+"'",con);
con.Open();
SqlDataReader dr=cmd.ExecuteReader();
dr.Read();
string Bulunan=dr["CompanyName"]+" "+dr["ContactName"]+" "+dr["Phone"];
con.Close();
return Bulunan;
        }
    }
}

Burada görüldüğü gibi remote object (uzak nesne) sınıfı için en önemli unsur, bu sınıfın System.MarshalByRefObject sınıfından türetilmiş olmasıdır. Normal şartlarda geliştirdiğimiz bu nesneye, bulunduğu sistemin application domain' i içerisinden direkt olarak erişebiliri. Ancak, bu nesnenin application domain' in dışındaki bir domainden kullanılabilmesini sağlamak yani remoting desteğini vermek için MarshalByRefObject sınıfından türetmemiz gerekmektedir. Bu sayede istemci uygulama, bu nesneye ait proxy nesnesi üzerinden mesaj gönderebilecek ve alabilecektir. Şimdi geliştirdiğimiz bu assembly' ı bir dll olarak aşağıdaki gibi derleyeylim.

Artık uzak nesnemizede sahip olduğumuza göre, bu nesneyi kullanacak istemcileri takip edecek, bir başka deyişle dinleyecek (listening) bir server (sunucu) uygulaması yazabiliriz. Bir sunucu uygulaması için en önemli unsurlar, dinleme işlemi için hangi kanalın, hangi ayarlar ile kullanılacağı ve remote object (uzak nesne) sınıfına ait bilgilerin ne olduğundan oluşmaktadır. Server (sunucu) için gerekli bu bilgileri uygulama içerisinden programatik olarak belirleyeceğimiz gibi, xml tabanlı bir konfigurasyon dosyası yardımıylada tanımlayabiliriz. XML tabanlı konfigurasyon dosyasının, programatik olan tekniğe göre en büyük avantajı, kanal ve remote object (uzak nesne) ile ilgili düzenlemelerde, kodun yeniden derlenmesine gerek kalınmamasıdır. Bir konfigurasyon dosyası, config uzantılıdır. Bu makalemizde kullancağımız Server (sunucu) uygulamaya ait konfigurasyon dosyası Sunucu.config isminde olup, aşağıdaki satırlardan oluşmaktadır.

<configuration>
    <system.runtime.remoting>
        <application name="MusteriUygulama">
            <service>
                <wellknown mode="SingleCall" type="UzakNesne.Musteriler,UzakNesne" objectUri="UzakNesne"/>
            </service>
            <channels>
                <channel ref="tcp server" port="1000"/>
            </channels>
        </application>
    </system.runtime.remoting>
</configuration>

Şimdi bu xml dosyasının içeriğini kısaca incelemeye çalışalım. Öncelikle ana eleman <configuration> dır. Burada server (sunucu) uygulamasına ait remote object (uzak nesne) ve channel (kanal) ayarlamaları mutlaka, <system.runtime.remoting> elemanı içinde yapılmalıdır. <application> elemanı içinde name özelliği ile server (sunucu) uygulamamızın adını belirtiyoruz.

Asıl önemli olan iki eleman <application> elemanı altında yer alan <service> ve <channels> elemanlarıdır. <service> elemanı altında <wellknown elemanı ile, remote object' e ait bilgiler belirtilir. mode niteliğinde, SingleCall ile, sunucu taraflı etkinleştirme tekniği belirtilmektedir. Bu anlamda SingleCall ile, istemci tarafından yapılan her metod çağırısına karşılık birer sunucu nesnesi örneği oluşturulması sağlanmaktadır. Diğer alternatif ise, Singleton tekniğidir ki bu tekniğe göre sunucu nesneyi kullanan kaç istemci olursa olsun, her bir istemcinin metod çağırımları sunucu tarafındaki tek bir nesne örneği tarafından yönetilmektedir.

type niteliğinde remote object (uzak nesne) için, bu tipin hangi isim alanı ve sınıfa ait olduğu belirtilir. type niteliğindeki ikinci parametre ise, uzak nesnenin bulunduğu assembly' ın adıdır. objectUri ile, istemcilerin uzak nesne için kullanacakları endpoint (son nokta) ismi belirtilmektedir. <channel elemanında, hangi protokol üzerinden ve hangi port' tan dinleme yapılacağı belirtilir. Burada sistemdeki machine.config dosyasında daha önceden tanımlanmış olan tcp server protokolünün, 1000 numaralı portu kullanacağı belirtilmiştir. Machine.config dosyasını  D:\WINDOWS\Microsoft.NET\Framework\vx.x.xxxx\CONFIG klasöründe bulabilirsiniz. Bu dosyada <channels> elemanı altında önceden tanımlanmış remoting protokolleri yer almaktadır.

<channels>
    <channel id="http" type="System.Runtime.Remoting.Channels.Http.HttpChannel, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <channel id="http client" type="System.Runtime.Remoting.Channels.Http.HttpClientChannel, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <channel id="http server" type="System.Runtime.Remoting.Channels.Http.HttpServerChannel,  System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <channel id="tcp" type="System.Runtime.Remoting.Channels.Tcp.TcpChannel, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <channel id="tcp client" type="System.Runtime.Remoting.Channels.Tcp.TcpClientChannel, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    <channel id="tcp server" type="System.Runtime.Remoting.Channels.Tcp.TcpServerChannel, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</channels>

Burada Machine.config içindeki tcp server protokolüne ait tanımlamada, System.Runtime.Remoting.Channels.Tcp. TcpServerChannel tipininde belirtildiğine dikkat edelim. Konfigurasyon dosyasının hazırlanması ile birlikte, artık sunucu uygulamamızı yazabiliriz. Sunucu uygulama, bu konfigurasyon dosyasını kullanarak, belirtilen protokol ve port üzerinden istemci taleplerini (mesajlarını) dinlemeye alacak ve gelen bu talepleri, yine konfigurasyon dosyasında belirtilen uzak nesneye ait örneğe yönlendirecektir. Nesneden dönen cevaplarda, yine bu konfigurasyon dosyasında belirtilen protokol ve port ile istemcilere gönderilecektir. Gelelim server(sunucu) uygulamamızın kodlarına.

using System;
using System.Runtime.Remoting;

namespace Sunucu
{
    public class SunucuDinler
    {
        public static void Main(string[] args)
        {
            RemotingConfiguration.Configure("Sunucu.config");
            Console.WriteLine("Dinlemeye baslandi...Çikmak için bir tusa basin");
            Console.ReadLine(); 
        }
    }
}

Burada görüldüğü gibi, sunucu uygulamamız konfigurasyon dosyasındaki bilgilere RemotingConfiguration sınıfının Configure metodu ile ulaşmaktadır. İzleyen satırlardaki WriteLine ve ReadLine metodları ile, uygulamanın biz son verene kadar 1000 nolu Tcp Server portunu dinlemesi sağlanmıştır. Şimdi yazdığımız bu uygulamayı exe olarak derleyelim.

Bu işlemlerin ardından, sunucu nesnemizin, sunucu uygulamamızın ve konfigurasyon dosyamızın aynı klasörde olmalarına dikkat edelim.

Artık sunucu tarafındaki işlemlerimizi bitirmiş olduk. Şimdi sunucu tarafındaki nesneyi kullanacak istemci uygulamayı tasarlayalım. Elbetteki, istemci uygulamada, mesajlarını Tcp protokolünü baz alarak bir kanal üzerinden göndermek zorundadır. Çünkü sunucu uygulama Tcp protokolünü baz alarak dinleme gerçekleştirecektir. Bunu sağlamak için öncelikle, istemci tarafında, client channel (istemci kanal) nesnesine ihtiyacımız vardır. İlave olarak, kullanacağımız uzak nesneninde bir koypasını, istemci uygulamanın assembly'ının bulunduğu klasöre koymamız gerekiyor. Bir istemci uygulama için önemli olan unsurlar, kanal nesnesi ayarları ve uzak nesneye ait ayarlardır. Bu ayarlamaları programatik olarak yapabileceğimiz gibi bir konfigurasyon dosyasında da yapabiliriz. Bu amaçla öncelikle aşağıdaki istemci.config dosyasını oluşturalım.

<configuration>
    <system.runtime.remoting>
        <application name="Istemci">
            <client>
                <wellknown type="UzakNesne.Musteriler,UzakNesne" url="tcp://localhost:1000/UzakNesne"/>
            </client>
            <channels>
                <channel ref="tcp client"/>
            </channels>
        </application>
    </system.runtime.remoting>
</configuration>

<wellknown elemanında proxy nesnesi ile iletişim kuracak uzak nesneye ait bilgiler yer almaktadır. Özel olarak, uzak nesnenin tam olarak adresi url bilgisinde belirtilmiştir. Bu url bilgisi, istemci uygulamadaki proxy nesnesinin mesajlaşmak amacıyla kullanacağı karşı nesne adresini tam olarak belirtmektedir. <channels> elemanında ise, client channel nesnesi belirtilmiştir. Bu nesne yine ref niteliği ile, sistemde machine.config dosyasında daha önceden tanımlanmış tcp client niteliğini referans etmektedir. Artık istemci uygulamamızıda yazabiliriz.

using System;
using System.Runtime.Remoting;

namespace istemciUygulama
{
    public class istemci
    {
        public static void Main(string[] args)
        {
            RemotingConfiguration.Configure("istemci.config");
            UzakNesne.Musteriler m=new UzakNesne.Musteriler();
            string sonuc=m.MusteriBul("ALFKI");
            Console.WriteLine(sonuc);
            Console.ReadLine();
        } 
    }
}

Görüldüğü gibi istemci uygulamada, konfigurasyon ayarlarını almak için RemotingConfiguration sınıfının Configure metodunu kullanır. Bundan sonra tek yapılan uzak nesne örneğini oluşturmak ve ilgili metodu çağırmaktır. Yazdığımız bu istemci.cs dosyasını aşağıdaki şekilde derleyeylim.

Burada dikkat edilecek olursa, uzaknesne.dll dosyası assembly'a referans olarak bildirilmiştir. Dolayısıyla, uzaknesne.dll' inin bir kopyasının istemci uygulamanın bulunduğu klasörde olması gerektiğine dikkat etmeliyiz.

Şimdi remoting sistemimizi bir test edelim. Öncelikle sunucu uygulamamızı, istemcilerden gelecek talepleri dinlemek amacıyla başlatmamız gerekiyor.

Bu işlemin ardından istemci uygulamamızıda çalıştıralım. Sonuçlar aşağıdaki gibi olacak ve sql sunucusunda yer alan Northwind veritabanındaki Customers tablosundaki CustomerID değeri ALFKI alan satır bilgileri elde edilecektir.

Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde görüşmek dileğiyle hepinize mutlu günler dilerim.

Yorumlar (1) -

  • Hocam merhabalar. Öncelikle makale için çok teşekkürler, ellerinize sağlık. UzakNesne projemizi derledikten sonra elde ettiğimiz UzakNesne.dll'i istemci uygulamanın referanslarına eklememiz gerekmez miydi? Eklemeden UzakNesne içerisindeki Musteriler sınıfından nasıl instance alırız?

Yorum ekle

Loading