Java RMI ile Chat Uygulaması Geliştirme

Java RMI (1)

Bu yazımda sizlere Java RMI teknolojisinin genel özelliklerinden ve bu teknolojiyi kullanarak örnek bir chat uygulamasının nasıl geliştirileceğinden bahsedeceğim.

Konuya girmeden önce, bir iki noktaya açıklık getirmek istiyorum :

  1. İnternette hemen hemen her konuyla ilgili yüzeysel bilgi bulmak çok kolay. Birazcık derinliği olan bir şeyler aramaya kalktığınızda ise işler hemen karışıyor çünkü istediğiniz bilgiyi bulana kadar yüzlerce sayfaya girmeniz gereke biliyor. Java RMI konusunu anlatırken daha önceden bulmakta zorlandığım bilgileri vermeye özen göstereceğim.
  2. Yazıyı Türkçe yazdım. Terimlerin Türkçeleştirilmesi için özel bir çaba harcamayacağım. Bu konuyla ilgili kişisel görüşüm bunun gereksiz olduğudur. Anlatımı daha anlaşılabilir kıldığını düşündüğüm yerlerde İngilizce terimler ile ilgili kısa kısa açıklamalarda bulunacağım.

Java Remote Method Invocation (RMI)

Java RMI, Java programlama dilinin Remote Method Invocation teknolojisidir. Java RMI teknolojisi sayesinde java programlama dilinde yazılmış programlar birbirleriyle network üzerinden konuşabilmektedir.

Remote Method Invocation Türkçe’ye Uzaktan Fonksiyon Çağırma olarak çevirilebilir(Bu çeviriyi başka bir yerde kullanmasanız iyi olur 🙂 ).  RMI yöntemi hemen hemen her programa dilinde implemente edilmiştir. Biz özel olarak Java Dilindeki implementasyon detaylarıyla ilgileneceğiz.

Java RMI uzak bir makinada bulunan bir java objesinin bir fonksiyonunu çağırmamıza olanak sağlamaktadır. Bunu yaparken hiçbir network bağlantı problemi ile uğraşmamıza gerek yoktur.

Java RMI’ın sağladığı servislerin hepsini Java Sockets ile kendimiz geliştirebiliriz ve bu tabiki Amerka’nın yeniden keşfi olacağı için öğrenmek dışındaki başka amaçlar için mantıklı olmayacaktır. Diyelim ki biz kendi RMI teknolojimizi geliştirmek istiyoruz. Bu durumda ne gibi problemleri çözmemiz gerekirdi:

  1. Fonksiyonunu çağırmak istediğimiz objenin hangi makinada bulunduğunu anlamamızı yarayacak bir sistem geliştirmemiz gerekirdi.(Java rmiregistry)
  2.  Fonksiyonun parametrelerinin ve adının ağ üzerinden uzaktaki makinaya iletilmesi için bir sistem geliştirmemiz gerekirdi(Java Serialization).
  3.  Localde uzak bir objenin çağırıldığı ile ilgili detayları saklamak için bir sistem geliştirmemiz gerekirdi. Bu uygulamamızın okunabilirliğini ve kullanılabilirliğini artıracaktır(Stub ve ya Proxy objeleri).
  4.  Fonksiyonun sonucunu fonksiyonu çağıran uygulamaya gönderecek bir sistem geliştirmemiz gerekirdi(Java Serialization).

Java RMI teknolojisi bizim yerimize yukarıda sıraladığımı problemleri çözmektedir ve Java uygulamalarında kullanmak üzere RMI teknolojisi sunmaktadır.

Java RMI ile İlgili Temel Kavramlar

rmiregistry

Uzak programların erişimine açılan objelerin kayıtlarının tutulduğu kayıt sistemidir. Bu kayıt sistemi sayesinde erişmek istediğimiz objeye bir isim ile ulaşabiliyoruz. Tabiki bunun olabilmesi için daha önceden birisinin aynı isimle bir obje kaydı yapmış olması gerekmektedir. rmiregistry java ile beraber gelen bir uygulamadır. Kendi yazdığımız uygulamayı çalıştırmadan önce bu uygulamanın çalışıyor olması gerekmektedir. rmiregistry’e obje kaydı sadece localden yapılabilmektedir. Bunun sebebi ise rmiregitry’de hiçbir Authentication ve Authorization sisteminin olmamasıdır, yani temel sebep güvenlik.

Stub Objeleri

rmiregistry sayesinde uzak bir objeye erişim sağladığımız zaman rmiregistry bize proxy(java dilinde bunun adı Stub’dır)objesi dönmektedir. Bu objenin normal java objelerinden hiçbir farkı yoktur. Bu objeyi programımızda tıpkı diğer java objeleri gibi kullanabiliriz. Bu objenin fonksiyonlarına yapılan bütün çağrılar otomatik olarak network üzerinden uzaktaki makinaya gönderilmektedir ve objenin fonksiyonu, objeyi rmiregistry’e kaydeden programda çalışmaktadir. Fonksiyonun sonucu ise network üzerinden tekrar proxy objeye gönderilmektedir. Stub objeleri RMI ile ilgili gerekli bütün network iletişimini kullanıcıdan saklamaktadır. Stub objesinin kullanıcısı local bir objenin fonksiyonunu çağırdığını düşünmektedir.

Serialization

Program içerisindeki objenin başka bir ortama aktarılması için objenin binary olarak ifadesidir. Buna objenin text olarak temsili de diyebiliriz. Aynı binay datanın daha sonradan objeye dönüştürülmesi ise  deserializationdır. Java RMI teknolojisi bizim için serialization ve deserialization işlerini yapmaktadır. Bu işlem network üzerinden obje göndermek için gerekmektedir.

Java RMI Teknolojisinin Temel Çalışma Mantığı – Chat Uygulaması

Java RMI teknolojisinin temel çalışma mantığını daha iyi anlatabilmek için bir java chat uygulaması yazdım. Bu uygulama sayesinde adım adım Java RMI teknolojisinin nasıl çalıştığını inceleyeceğiz. Uygulamanın kaynak koduna github sayfamdan ulaşabilirsiniz. Yazımın bundan sonraki kısmında bu örnek uygulamayı inceleyeceğiz.

Burada önemli nokta şu, internette heryerde “helloworld” RMI ugulaması bulmak kolay. Bu uygulamalar çoğunlukla Client dan Server a iletişimi anlatmaktalar. Biz chat uygulaması sayesinde server’dan uygulamadan client uygulamaya nasıl data gönderilebileceğini de göreceğiz.

Java RMI (1)
Java RMI Chat Uygulaması Mimarisi

Öncelikle rmiregistry uygulaması server uygulamanın çalışacağı makinada çalıştırılır.

  1. Server uygulaması, bir adet server objesini bir isim ile rmiregistry’e kayıt eder(resimdeki 1 numaralı ok).
  2. Chat client uygulaması bu işlemden sonra çalıştırılır.
  3. Chat client uygulaması Server Objesine erişmek için bir isim ile rmiregistrye sorgu yapar(resimdeki 2 numaralı ok).
  4. rmiregistry istenilen isimde bir obje varmı diye bakar, eğer obje varsa objeyi isteği yapan cliente gönderir(resimdeki 3 numaralı ok).
  5. Client aldığı objeyi normal bir java objesi gibi kullanır. Arka planda bu objeye yapılan bütün istekler server uygulamasına gönderilir, server uygulamasında çalışır ve sonuçlar tekrar client uygulamasına gönderilir(resimdeki 4 numaralı ok).

Client rmiregistry’den obje referansını aldıktan sonra, bütün iletişim objeyi sağlayan bilgisayar ve client arasında olmaktadır. Yani bizim örneğimizde iletişim Client ve Server uygulamalar arasında olmaktadır.

Chat Uygulaması Server Interface

Chat Server interface’i ChatServer.java dosyasındadır. Kodu aşağıda görebilirsiniz.

  • rmiregistry den server objesine erişen bütün client uygulamaları öncelikle registerClient methodunu kullanarak servera kendisini kaydetmelidir. Bu fonksiyon kayıt işlemini yaptıktan sonra, sonuç olarak serverda kayıtlı diğer clientların isimlerini dönüyor. Bu sayede diğer clientların isimleri yani hangi kullanıcıların online olduğu bilgisi register onlan Client’a iletilmiş oluyor.
  • Client uygulaması kapanırken unregisterClient fonksiyonunu kullanarak kedisinin server kaydından silmelidir. Bu sayede diğer kullanıcılara bir kullanıcının offline olduğu bilgisi Server tarafından iletilmektedir.
  • Bir Client uygulaması başka bir Client ugulamasına mesaj göndermek istediği zaman sendMessage fonksiyonunu çağırarak mesaj göndermektedir.

Chat Uygulaması Client Interface

Chat Client interface’i ChatClient.java dosyasındadır. Kodu aşağıda görebilirsiniz.

  • getName fonksiyonu client’ın isim bilgisine erişmek için kullanılmaktadır. Yani kullanıcın adına erişmek için.
  • notifyLogin fonksiyonu Server uygulaması tarafından çağırılmaktadır. Server objesinde bir Client registrerClient fonksiyonunu çağırarak kayıt işlemi yapmaya çalıştığı zaman, kayıt işlemi yapan kullanıcının isim bilgisi diğer bütün kayıtlı clientların notifyLogin fonksiyonu çağırılarak clientlara iletilmektedir. Bu sayede client uygulamasının online kişiler listesini güncellenmektedir.
  • notifyLogout gene server uygulamasından çağırılan bir fonksiyondur. Server objesinin unregisterClient fonksiyonunu çağırarak logout olmak isteyen client ismi diğer bütün clientlara notifyLogout fonksiyonu sayesesinde iletilmektedir. Bu sayede client uygulamasının online kişiler listesini güncellemektedir.
  • notifyMessage fonksiyonu Server uygulaması tarafından çağırılmaktadır. Server objesinin sendMesssage fonksiyonu kullanılarak iletilmek istenen mesaj, notifyMessage fonksiyonu kullanılarak ilgili client objesine iletilir. (Server Uygulaması register olmuş bütün clientları kayıt etmektedir. Bir mesaj isteği geldiğinde kayıtlı clientların listesinde isme göre arama yaparak mesajın gönderileceği client bulunur ve bu client’ın notifyMessage fonksiyonu çağırır.)

Java RMI kullanımı ile ilgili önemli noktalar

  • Chat uygulamasındaki client ve server interfacelerini beraber inceledik. Java RMI kullanarak remote method invocation yapılacak bütün objelerin Remote interface’ini extend eden bir Interface’i implemente etmeleri zorunludur. Şuana kadar biz sadece interfaceleri gördük. İmplementasyon classlarını daha sonra göreceğiz.
  • Remote interface extend ederken fonksiyonlardaki throws RemoteException kısmını unutmayınız. Bunu unutursanız hata alırsınız.
  • Java RMI kullanarak iletişim fonksiyon çağırma şeklinde olmaktadır. Remote objesinin bir fonksiyonunu çağırırız ve bize bir sonuç döner.

Chat Uygulaması Server Implementasyonu

Server impelemtasyonunun kodu Server.java dosyasındadır. Kodu aşağıda görebilirsiniz.

  • Burada kayıtlı Client’ların listesini tutmak için bir adet map objemiz var. Map objemize clientları client ismi ve client objesi şeklinde kaydediyoruz. Bu sayede bir client’a mesaj isteği olduğu zaman ilgili client’ı hızlı bir şekilde ismi ile arayarak map içerisinden bulabiliyoruz.
  • registerClient fonksiyonu çağırıldığında map objemize yeni client objesi konulmakta ve diğer client’lara yeni bir kullanıcının login olduğu bilgisi notifyLogin fonksiyonu çağırılmak süretiyle iletilmekte. Ayrıca registerClient fonksiyonunu çağıran client’a zaten login olmuş clienların isim listesi geri dönülmekte.
  • unregisterClient fonksiyonu çağırıldığında, çağıran client’a ait client objesi map objemizden silinir ve diğer bütün clientlara bu bilgi yani bir client’ın offline olduğu bilgisi clientların notifyLogout fonksiyonu çağırılmak süretiyle iletilir.
  • sendMessage fonksiyonu çağırıldığında mesajın alıcısı olan client map objemizden aranarak bulunur ve bulunan client objesinin notifyMessage fonksiyonu çağırılmak süretiyle mesaj alıcısına iletilir.

Chat Uygulaması Client Implementasyonu

Client implementasyon codu Client.Java dosyasındadır. Kodunu aşağıda görebilirsiniz.

Client implementasyonunda online kullanıcıların isimlerini tutmak için kullandığımız bir adet Set objemiz var

  • notifyLogin fonksiyonu çağırıldığı zaman login olan client’adı set objemize eklenmekte.
  • notifyLogout fonksiyonu çağırıldığında offline olan kullanıcı ismi set objemizden silinmekte.
  • notifyMessage fonksiyonu çağırıldığında gelen mesaj kimden geldiği bilgisi ile birlikte konsola yazılmakta.
  • getName fonksiyonu çağarıldığında client ismi yani kullanıcı ismi çağıran kişiye dönülmekte.

Server uygulaması

Server uygulamasının kodu ServerApp.java dosyasındadır. Server uygulaması çalıştırmak isteyen kullanıcılar bu dosyadaki main fonksiyonunu çalıştırmalılar. Kodu aşağıda görebilirsiniz.

  • Satır 23 de rmiregistry uygulamasının 2020 portunda çalıştırıldığını görüyoruz.
  • Satır 26’da bir adet Server objesi oluşturuyoruz
  • Satır 27 en önemli noktalardan birisi, burada UnicastRemoteObject.exportObject fonksiyonunu çağırarak bir adet Stub objesi oluşturuyoruz. Stub objelerinine erişimde sadece interface methodları kullanılabilir. RMI’da kullanılacak bütün objelerin Stub olması gerekmektedir.
  • Satır 31 de localde çalışan rmiregistry uygulamasına bağlanılıyor
  • Satır 32 de ise serverStub  objemiz “ChatServerObject” ismi ile rmiregistry’e kaydediliyor. Bu noktadan sonra client uygulamalarımızı çalıştırabiliriz.

Client Uygulaması

Client uygulamasının kodu ClientApp.java dosyasındadır. Client uygulaması çalıştırmak isteyen kullanıların bu dosyadaki main fonksiyonunu çalıştırmaları gerekmektedir. kodu aşağıda görebilirisiniz.

  • Burada önemli noktaların üzerinde durabilmek açısından komut satırı kullanıcı ara yüzü ile ilgili kodları yukarıda vermedim.
  • Satır 32 de rmiregistry uygulamasına bağlanıyoruz.
  • Satır 39 da bir adet Client objesi yaratıryoruz.
  • Satır 40 da Client Stub objesi yaratıyoruz.
  • Satır 42 de “ChatServerObject” ismi ile rmiregistry de kayıtlı olan Server objesine erişiyoruz.
  • Satır 43 de server objesinin registerClient methodunu kullanarak Client Stub objemizi servera kaydediyoruz ve yukarıda gördüğümüz üzere Server objesi kayıtlı bütün client’lara yeni bir kullanıcının login olduğu bilgisini yeni kullanıcının isim bilgisi ile birlikte iletmekte. Bu işlemin sonucunda serverda zaten kayıtlı olan kullanıcıların isimlerini alıyoruz ve Client objesinin addCurrentUsers methodunu çağırmak süretiyle bu kullanıcıları online kullanıcılar Setimize ekliyoruz.

Kodun bundan sonraki kısmı kullanıcı ara yüze ile ilgili.

Hatırlatmalar

  1. rmiregistry ayrı bir uygulama, java kurulumu ile gelmekte.
  2. RMI ile kullanılacak objelerin Stub objelerinin yaratılması gerekmekte.
  3. Stub objeleri sadece ve sadece dışarıdan erişim sağlanmak istendiğinde rmiregistry kaydedilmeli. Bizim örneğimizde Server objesi rmiregistry’e kaydedildi çünkü bu objenin bütün clientlar tarafından erişilmesi gerekmekte yani bu sistemi kullanacak herkesin bu objeye ihtiyacı var.
  4. RMI da kullanılacak objelerin hepsinin rmiregistry e kaydedilmesi gerekmemektedir. Bu objeler fonksiyon çağırmak suretiyle başkalarına aktarılabilir(Client objelerini server’a göndermek ve onları daha sonra serverda kullanmak üsere saklamak için server objesinin registerClient methodunu kullanıyoruz).
  5. Java RMI chat uygulamasının github sayfasındaki README dosyasını okumayı unutmayınız.

Soru ve önerileriniz için yorum bırakabilirsiniz. İyi çalışmalar.

Java RMI ile Chat Uygulaması Geliştirme” için bir yorum

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s