3. diel - Java RMI - Volanie zo servera na porte 2020
V minulej lekcii kurzu o RMI v Jave sme si zavolali vzdialenú metódu na serveri. V dnešnej lekcii si vyskúšame použitie nedefaultního portu. V našom prípade použijeme RMI registre na porte 2020. Prakticky sa jedná o RMI registre, ktoré sme si vytvorili v dieli nastavenie prostredia. Avšak pozor, je nutné nezabudnúť, že RMI registre nastavujeme pre daný projekt (Working directory). Inak bude aplikácia padať. V tomto príklade bude mať každá trieda (server aj klient) používajúce RMI ako svoj skeleton tak i stub toho druhého.
Tento príklad teda bude podobný príkladu v predchádzajúcej lekcii, avšak využijeme iný port pre RMI registre, vyskúšame si volanie zo servera na klienta / z klienta na server. Opäť sa bude jednať o konzolovú aplikáciu koncepte server / klient. Všetko budeme simulovať na localhost. Celý postup sa prakticky opäť skladá zo 4 krokov, ktoré si tu uvedieme.
- Naprogramujeme si rozhranie pre zdieľané objekty, ktoré budeme cez RMI zdieľať
- Naprogramujeme serverovú časť, spustíme RMI registre a spustíme server
- Naprogramujeme klientskú časť a spustíme klienta
- Sledujeme a kontrolujeme výstupy
Programovanie rozhranie pre zdieľané objekty
Opätovne naprogramujeme rozhranie, ktoré bude zdedené od rozhrania java.rmi.Remote. Klient musí implementovať dve metódy a server iba jednu.
Rozhranie pre klienta:
package rozhrani.klient; public interface RozhraniKlient extends java.rmi.Remote { void volameKlientMetoda1() throws java.rmi.RemoteException; void volameKlientMetoda2() throws java.rmi.RemoteException; }
Rozhranie pre server:
package rozhrani.server; public interface RozhraniServer extends java.rmi.Remote { void volameServerMetoda1() throws java.rmi.RemoteException; }
Programovanie serverovej časti, spustenie RMI registre a spustenie servera
Opätovne si naprogramujeme server (napr. Class ServerRMI), ktorý bude implementovať zdieľané rozhranie, ktoré sme napísali vyššie. Z implementovaného rozhrania nám vznikla povinnosť doprogramovať vnútro jedinej metódy "volameServerMetoda1 ()". Zdrojový kód serveru som napísal bez importov, môžete si ich dodať a kód tak zjednodušiť.
/* Program potřebuje registry na defaultním portu 2020 */ package server; public class ServerRMI implements rozhrani.server.RozhraniServer { private static rozhrani.server.RozhraniServer rozhrServer = null; private static java.rmi.registry.Registry registry = null; public void volameServerMetoda1() throws java.rmi.RemoteException { System.out.println("Metoda zavolana na serveru"); try { Thread.sleep(5000); // uspíme vlákno na 5 sekund } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Zavolame metody na klientovi"); rozhrani.klient.RozhraniKlient rozhObjektKlient= null; try { rozhObjektKlient = (rozhrani.klient.RozhraniKlient) registry.lookup("KlientRMI"); } catch (java.rmi.RemoteException | java.rmi.NotBoundException e) { System.out.println("Nepodarilo se ziskat objekt stubu (rozhrani)"); e.printStackTrace(); } System.out.println("Zavolame si metody na klientech"); try { rozhObjektKlient.volameKlientMetoda1(); rozhObjektKlient.volameKlientMetoda2(); } catch (java.rmi.RemoteException e) { System.out.println("Nepodarilo se zavolat metodu na klientovi"); e.printStackTrace(); } } public static void main(String[] args) { System.out.println("Spustime RMI server"); // vytvoříme objekt rozhraní (tzv. skeleton) try { rozhrServer = (rozhrani.server.RozhraniServer) java.rmi.server.UnicastRemoteObject.exportObject(new ServerRMI(),0); } catch (java.rmi.RemoteException e) { System.out.println("Nepodarilo se nam vytvorit skeleton"); e.printStackTrace(); } // získáme objekt RMI registru pro daný port try { registry = java.rmi.registry.LocateRegistry.getRegistry(2020); } catch (java.rmi.RemoteException e) { System.out.println("Nepodarilo se ziskat objekt RMI registru"); e.printStackTrace(); } // nahrajeme skeleton do registru try { registry.bind("ServerRMI",rozhrServer); } catch (java.rmi.RemoteException | java.rmi.AlreadyBoundException e) { System.out.println("Nepodarilo se nahrat skeleton do registru"); e.printStackTrace(); } System.out.println("Cekame na volani Klienta"); } }
Tu si rozoberieme čo vlastne zdrojový kód robí. V prvej časti (public static void main () metóde) si vytvoríme objekt (inštanciu) triedy implementujúce zdieľané rozhrania. Potom získame objekt RMI registra a už len nahráme zdieľaný objekt do RMI registrov. Týmto spôsobíme vznik tzv. Skeleton. Skeleton pomenujeme, presnejšie mu priradíme identifikátor, "ServerRMI". Samozrejme meno identifikátora je voliteľné a takých Skeleton môžeme nahrať do RMI registrov koľko chceme. Nie som si vedomý obmedzenia čo sa týka počtu nahraných skeleton. Zaiste ste si všimli, že metóda získanie RMI registrov má tentoraz parameter 2020. Áno, tento parameter špecifikuje port (viac pozri Java dokumentácia). Teoreticky by sme mohli aj vyskúšať spustiť viac RMI registrov na rôznych portoch a do nich nahrať inej SKELETON, ale čo z toho? Fungovať by to najskôr malo. Metóda volameServerMetoda1 () je metódou, ktorá je k dispozícii stub na klientovi. Pokiaľ ju zavolá, potom v metóde vytvoríme stub klienta a tým získame metódy, ktoré má zdieľaný objekt na klientovi k dispozícii.
Tu si celý kód ukážeme v IDE. V druhej časti (volameServerMetoda1 () metóde) sa vykoná najskôr uspanie na 5 sekúnd, potom si vytvoríme zrkadlový objekt Stube klienta a zavoláme obe jeho metódy, ktoré sú (budú) na klientovi k dispozícii. Oneskorenie 5 sekúnd je tam len aby ste prepli výpis konzoly v IDE a mohli sa presvedčiť o výpisu na klientovi na vlastné oči.
Zaiste ste si všimli, že kód je navrhnutý tak, že sa spustí server, potom klient, klient zavolá metódu na serveri a v nej sa zas zavolajú metódy na klientovi. Samozrejme, mohol som to urobiť na priamo bez tej zdieľané metódy na serveri, kedy server priamo vytvorí stub klienta, ale chcel som, aby sme si to vyskúšali.
Programovanie klientskej časti a uspania klienta
Ako ďalšie vytvoríme triedu klienta (napr. Class KlientRMI). Ako ste si všimli, ide o štandardnú public static void main () metódu a je potrebné ju tak aj spustiť.
Kód je skutočne veľmi jednoduchý a je veľmi analogický s tým zo servera. Najskôr vytvoríme skeleton klienta, získame RMI registre z portu 2020 a potom skeleton nahráme s identifikátorom "KlientRMI" do RMI registra. Po tomto je skeleton klienta k dispozícii všetkým, ktorí disponujú rozhraním.
Ďalej vytvoríme zdieľaný objekt rozhrania servera (tzv. Stub) cez RMI registre. K tomu potrebujeme identifikátor, ktorý sme použili na serveri v RMI registroch. No a potom konečne máme objekt, ktorý disponuje našou metódou, ktorú sme si definovali v rozhraní.
package klient; import java.rmi.*; import java.rmi.registry.*; import rozhrani.klient.*; import rozhrani.server.*; public class KlientRMI implements RozhraniKlient { private static RozhraniKlient rozhrKlient; public void volameKlientMetoda1() throws RemoteException { System.out.println("Klient RMI metoda1"); } public void volameKlientMetoda2() throws RemoteException { System.out.println("Klient RMI metoda2"); } public static void main(String[] args) { System.out.println("Spustime RMI klienta"); // vytvoříme objekt implementující rozhraní (tzv. skeleton) try { rozhrKlient = (RozhraniKlient) java.rmi.server.UnicastRemoteObject.exportObject(new KlientRMI(),0); } catch (java.rmi.RemoteException e) { System.out.println("Nepodarilo se nam vytvorit skeleton"); e.printStackTrace(); } // získáme objekt RMI registru pro daný port Registry registry = null; try { registry = LocateRegistry.getRegistry(2020); } catch (RemoteException e) { System.out.println("Nepodarilo se ziskat objekt registru"); e.printStackTrace(); } // nahrajeme stub do registru try { registry.bind("KlientRMI",rozhrKlient); } catch (java.rmi.RemoteException | java.rmi.AlreadyBoundException e) { System.out.println("Nepodarilo se nahrat stub do registru"); e.printStackTrace(); } // zavoláme metodu na serveru RozhraniServer rozhObjektServer = null; try { rozhObjektServer = (RozhraniServer) registry.lookup("ServerRMI"); } catch (RemoteException | NotBoundException e) { System.out.println("Nepodarilo se ziskat objekt stubu (rozhrani)"); e.printStackTrace(); } System.out.println("Zavolame si metodu na serveru"); try { rozhObjektServer.volameServerMetoda1(); } catch (RemoteException e) { System.out.println("Nepodarilo se zavolat metodu na serveru"); e.printStackTrace(); } System.out.println("Cekame na volani Serveru"); } }
Teraz si spustíme opätovne RMI registre na porte 2020.
Spustíme aj server a pozrieme si výpis na konzole.
Teraz si spustíme klienta a pozrieme si výpis na konzole. Prepneme na server a pozrieme sa na výpis konzole.
No a teraz sa zas prepneme sa na výpis konzole klienta. Krásne ide vidieť zavolané metódy na klientovi.
V budúcom dieli si preberieme trochu ďalšie teórie ohľadom RMI.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 8x (6.65 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java