Σύνοψη 6 ης ιάλεξης Κατανεµηµένα Συστήµατα ΙΙ Μάθηµα Ελεύθερης Επιλογής, Εαρινού Εξαµήνου Τοµέας Εφαρµογών και Θεµελιώσεων Ιωάννης Χατζηγιαννάκης Τετάρτη, 7 Μαΐου, 2008 Αίθουσα ΑΠ7 Κατανεµηµένα Συστήµατα ΙΙ Κατανεµηµένα Αντικείµενα Κύκλος Ζωής Ροή Εκτέλεσης Τεχνολογίες Υλοποίησης Ενδιάµεσα Λογισµικά Αντικειµενοστραφής Προγραµµατισµός σε JAVA Sockets Remote Method Invocation -- RMI Παράδειγµα RMI 1 Παράδειγµα RMI 2 Σύνοψη Μαθήµατος Σύνοψη Μαθήµατος Βιβλιογραφία Επόµενη ιάλεξη Εισαγωγικά (1) Ενα αντικείµενο χαρακτηρίζεται κατανεµηµένο όταν οι µέθοδοι του µπορούν να κληθούν εξ αποστάσεως παρόµοιο τρόπο µε την κλήση αποµακρυσµένων διαδικασιών Σε τοπικό επίπεδο, οι δείκτες στο κατανεµηµένο αντικείµενο απεικονίζονται τοπικά από ένα ειδικό, εξουσιοδοτηµένο αντικείµενο από το οποίο γίνονται οι κλήσεις (proxy/stub) Μια αναφορά σε ένα κατανεµηµένο αντικείµενο µπορεί να χρησιµοποιηθεί ως παράµετρος στην κλήση µιας αποµακρυσµένης διαδικασίας Ο εξυπηρέτης ϑα δηµιουργήσει ένα τοπικό, εξουσιοδοτηµένο αντικείµενο (proxy) σύµφωνα µε τον δείκτη στο κατανεµηµένο αντικείµενο Εισαγωγικά (2) Για κάθε αντικείµενο υπάρχει ένα αντικείµενο σκελετού (skeleton object) Για κάθε αποµακρυσµένη αναφορά υπάρχει ένα αντικείµενο εξουσιοδότης (proxy object) Το αντικείµενο εξουσιοδότης αντιστοιχεί στο client stub Το αντικείµενο σκελετού αντιστοιχεί στο server stub Η χρήση των µεθόδων του κατανεµειµένου αντικείµενου γίνεται µέσω του RM runtime Εξουσιοδοτηµένο αντικείµενο Κλήση διαδικασίας
Κύκλος Ζωής Κατανεµηµένων Αντικειµένων ηµιουργία, Καταχώρηση, Αναζήτηση Ενα κατανεµηµένο αντικείµενο δηµιουργείτε από την κλάση που το ορίζει µε την πρώτη αναφορά ίδιος τρόπος µε τα απλά, τοπικά, αντικείµενα Η µονάδα που δηµιούργησε το αντικείµενο είναι υπεύθυνη για την διαχείριση του Κάθε αποµακρυσµένη διεργασία που επιθυµεί να χρησιµοποιήσει το αντικείµενο, πρέπει να επικοινωνήσει µε την µονάδα που το δηµιούργησε (διαχειριστή) Η µονάδα διαχειριστής κρατάει δείκτες προς τις διεργασίες που έχουν Ϲητήσει πρόσβαση στο κατανεµηµένο αντικείµενο Ορισµένοι µηχανισµοί περισυλλογής άχρηστων αντικείµενων (Garbage Collection) ακολουθούν την ίδια τακτική Οταν ένα αντικείµενο δεν έχει κανένα δείκτη προς κάποια διεργασία, ϑεωρείτε άχρηστο και περισυλλέγεται Μία διεργασία εξυπηρέτης δηµιουργεί το πρώτο αντικείµενο σύµφωνα µε την κλάση που το ορίζει Καταχωρεί τα στοιχεία του αντικειµένου (και της κλάσης που το ορίζει) σε µια υπηρεσία καταλόγου σύµφωνα µε ένα όνοµα Οταν µια διεργασία πελάτης ϑελήσει να χρησιµοποιήσει το κατανεµηµένο αντικείµενο, το αναζητά µέσω της υπηρεσίας καταλόγου µε ϐάση το όνοµα Η αναζήτηση επιστρέφει πληροφορίες για την τοποθεσία της κλάσης του αντικειµένου, την ύπαρξη ή όχι αντικειµένου Αποµάκρυνση Αντικειµένων Περισυλλογή Αντικειµένων Ενα αντικείµενο µπορεί να µην χρησιµοποιηθεί για µεγάλο χρονικό διάστηµα για λόγους εξοικονόµησης πόρων, το σύστηµα αποµακρύνει τα ανενεργά αντικείµενα σε δευτερεύουσα µονάδα αποθήκευσης Οταν µια διεργασία χρησιµοποιήσει τον τοπικό εξουσιοδότη (proxy) το σύστηµα επαναφέρει το αντικείµενο στην πρωτεύουσα µονάδα αποθήκευσης (επαναφορά) Η αποµάκρυνση και επαναφορά αντιστοιχεί στην λογική διαχείρισης σελίδων εικονικής µνήµης Το σύστηµα (εξυπηρέτης) που δηµιούργησε το κατανεµηµένο αντικείµενο A, διατηρεί ένα διάνυσµα A.v Οταν µια διεργασία p (πελάτης) δηµιουργήσει έναν τοπικό εξουσιοδότη (proxy) για το κατανεµηµένο αντικείµενο Το σύστηµα εξυπηρέτης προσθέτει την p στο A.v Οταν µια διεργασία p (πελάτης) περισυλλέξει τον τοπικό εξουσιοδότη (proxy) -- δεν υπάρχει καµία (τοπική) αναφορά Το σύστηµα εξυπηρέτης αφαιρεί την p από το A.v Αν ένα αντικείµενο έχει κενό διάνυσµα για ορισµένο χρονικό διάστηµα το σύστηµα ϑεωρεί ότι δεν χρησιµοποιείτε: το αντικείµενο περισυλλέγεται
Τεχνολογίες Υλοποίηση Κατανεµηµένων Αντικείµενων (1) Java RMI Αυστηρά για Java Ο κώδικας proxy µπορεί να δηµιουργηθεί εκ των προτέρων για τους πελάτες DCOM / COM+ Corba Υποστηρίζει διαφορετικές γλώσσες Απευθύνεται στα Windows* Υποστηρίζει διαφορετικές γλώσσες Υλοποιείται σε όλα τα λειτουργικά Πλούσια λειτουργικότητα ιαφορετικοί στόχοι διαφορετικές τεχνικές ανάπτυξης Η κλάση που περιγράφει ένα κατανεµηµένο αντικείµενο υλοποιεί µία διεπαφή (interface Remote) ή/και επεκτείνει µια ϐασική κλάση (class RemoteObject) Η επέκταση της διεπαφής και ϐασικής κλάσης επιτρέπει στο σύστηµα εκτέλεσης να ανακαλύψει δυναµικά αν το συγκεκριµένο αντικείµενο είναι τοπικό ή κατανεµηµένο Η γλώσσα προγραµµατισµού δηµιουργεί αυτόµατα την κλάση εξουσιοδότη και την κλάση σκελετό Παρόµοιος τρόπος µε IDL Οι κλάσεις εξουσιοδότη και σκελετού αποθηκεύονται σε κάποιο διακοµιστή αρχείων για να είναι προσβάσιµα από τις αποµακρυσµένα µονάδες µέσω δικτύου Υλοποίηση Κατανεµηµένων Αντικείµενων (2) Παράδειγµα Υλοποίησης Σύνοψη 6 ης ιάλεξης Κατανεµηµένα Συστήµατα ΙΙ Κατανεµηµένα Αντικείµενα Κύκλος Ζωής Ροή Εκτέλεσης Τεχνολογίες Υλοποίησης Ενδιάµεσα Λογισµικά Αντικειµενοστραφής Προγραµµατισµός σε JAVA Sockets Remote Method Invocation -- RMI Παράδειγµα RMI 1 Παράδειγµα RMI 2 Σύνοψη Μαθήµατος Σύνοψη Μαθήµατος Βιβλιογραφία Επόµενη ιάλεξη
Η υλοποίηση µε RMI είναι σχεδόν πάντα πιο εύκολη και έχει µικρότερο κόστος σε σχέση µε κάποια υλοποίηση σε Sockets Η µετατροπή των δεδοµένων (προς µεταφορά) γίνεται εξολοκλήρου µε την χρήση της RMI Αν δεν µεταφέρουµε απλά στοιχεία (ASCII) µειώνουµε αρκετά τον απαραίτητο κώδικα Μπορούµε να επικοινωνήσουµε µε µεγαλύτερη ευκολία όταν παρεµβάλλονται firewalls -- η σύνδεση µπορεί να γίνει µέσω πρωτοκόλλου http Η µεταφορά λειτουργιών από τον πελάτη στον εξυπηρέτη είναι πολύ πιο εύκολη Ο κεντρικός στόχος δεν είναι µια αποδοτική υλοποίηση Η υλοποίηση µε RMI είναι ορισµένα αρνητικά στοιχεία Η χρήση του JAVA Serialization απαιτεί µνήµη (δηµιουργία νέων προσωρινών αντικειµένων) και επεξεργαστική ισχύ (µετατροπή δεδοµένων) Η τεχνολογία RMI ανήκει στην SUN -- η εξέλιξη της, η ϐελτίωση των υπάρχοντων λειτουργιών, η υποστήριξη εξαρτάται από την SUN Είναι αποκλειστικά για JAVA -- υπάρχουν τρόποι να ξεπεραστεί το πρόβληµα µε την χρήση της ϐιβλιοθήκης JNI Παρ ολα αυτά είναι πιο απλή από την CORBA Συντοµότερος χρόνος υλοποίησης Μπορεί να επιτευχθεί µε την χρήση ισχυρότερων µηχανηµάτων Βελτίωση στην απόδοση δεν γίνεται ποτέ εκ των προτέρων Απλό παράδειγµα χρήσης RMI Το αντικείµενο ϐρίσκετε στο µηχάνηµα URL addr = new URL("rmi://www.upatras.gr/ds2course"); Βασιζόµαστε στο πρωτόκολλο rmi και όχι στο http Απευθυνόµαστε στον κατάλογο της RMI (registry) του τοπικού µηχανήµατος Server server = (Server) Naming.lookup(addr); Η µέθοδος µας επιστρέφει µια αναφορά στο αντικείµενο που αναζητούµε, µε συγκεκριµένο τύπο στο παράδειγµα το αντικείµενο είναι τύπου Server Μόλις ϐρεθεί µια αναφορά, χρησιµοποιούµε το αντικείµενο σαν να ήταν ένα κανονικό τοπικό αντικείµενο float mark = server.getmymark(am); Μοναδική διαφορά η µέθοδος getmymark() µπορεί να δηµιουργήσει ένα σφάλµα τύπου RemoteException Υλοποιούµε τρεις συναλλαγές µεταξύ Πελάτη-Εξυπηρέτη (δύο υψηλότερα επίπεδα) Αναζήτηση Πτήσεων επιστρέφει όλες τις πτήσεις που υπάρχουν στη ϐάση δεδοµένων Αναζήτηση Θέσεων επιστρέφει όλες τις κρατήσεις που αφορούν ένα συγκεκριµένο πελάτη Κράτηση ϑέσης υποθέτουµε ότι η πτήση και ο πελάτης υπάρχουν ήδη στους πίνακες της ϐάσης δεδοµένων (για χάριν ευκολίας)
Οι συνιστώσες λογισµικού για την υλοποίηση σε RMI δεν είναι πολύ διαφορετικές από αυτές που χρησιµοποιούν Sockets Η ϐασική διαφορά είναι η απουσία των µεθόδων που προετοιµάζουν τα δεδοµένα για αποστολή δηλ. η συνιστώσα SuperSocket Το πρώτο ϐασικό ϐήµα είναι να καταχωρίσουµε στην RMI τις µεθόδους που ϑα προσφέρει ο εξυπηρέτης Βασιζόµαστε στο interface της RMI Remote Το επεκτείνουµε ορίζοντας το ServerInterface Ολες οι µέθοδοι του interface µπορεί να δηµιουργήσουν ένα σφάλµα τύπου RemoteException import java.rmi.*; import java.sql.sqlexception; public interface ServerInterface extends Remote { public Flight [] searchflights() throws RemoteException, SQLException ; public Reservation [] searchseats( String passenger_no) throws RemoteException, SQLException ; public void bookseat(string flight_no, String passenger_no, String res_no) throws RemoteException, SQLException, FlightBookedException ; Οι δύο πρώτες µέθοδοι επιστρέφουν ένα πίνακα στην Java οι πίνακες είναι αντικείµενα τα οποία µπορούν να σειριοποιηθούν Η συνιστώσα Server επεκτείνει την UnicastRemoteObject Εποµένως η RMI ϑα περάσει τις τιµές των αντικειµένων και όχι αναφορές σε αυτά Αν πολλοί πελάτες Ϲητήσουν το ίδιο αντικείµενο Flight ϑα πάρουν διαφορετικά αντίγραφα αντί για µια αναφορά στο ίδιο αντικείµενο Αν για κάποιο λόγο ϑέλουµε να περάσουµε αναφορές σε ένα αντικείµενο µπορούµε να χρησιµοποιήσουµε την µέθοδο exportobject που ορίζει η συνιστώσα UnicastRemoteObject import java.rmi.*; import java.rmi.server.*; import java.sql.*; public class Server extends UnicastRemoteObject implements ServerInterface { static final String SERVERNAME = "ARServer"; static final String DB = "jdbc:odbc:airline"; static final String USER = ""; static final String PASSWORD = ""; Connection theconnection; public Server() throws Exception { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); theconnection = DriverManager.getConnection(DB, USER, PASSWORD)
public static void main(string [] args) { System.setSecurityManager(new RMISecurityManager()); try { Server server = new Server(); Naming.rebind(SERVERNAME, server); System.out.println("Server ready."); catch (Exception ex) { ex.printstacktrace(); public Flight [] searchflights() throws RemoteException, SQLException { Flight [] flights = Flight.getFlights(theConnection); return flights; public Reservation [] searchseats(string passenger_no throws RemoteException, SQLException { Reservation [] res = Reservation.getPassenger( theconnection, passenger_no); return res; public void bookseat(string flight_no, String passenger_no, String res_no) throws RemoteException, SQLException, FlightBookedException { Reservation res = new Reservation( theconnection, res_no, flight_no,passenger_no); res.dbwrite(theconnection); Εκτέλεση RMI Server ηµιουργήστε ένα ϕάκελο και τοποθετήστε όλα τον κώδικα της υλοποίησης και την ϐάση δεδοµένων (airline.mdb) Ρυθµίστε τον οδηγό ODBC Κάντε compile τον κώδικα: javac *.java ηλώστε την συνιστώσα Server στον τοπικό κατάλογο της RMI: rmic Server Ξεκινήστε τον τοπικό κατάλογο της RMI: start rmiregistry Ξεκινήστε τον Εξυπηρέτη: java Server Υλοποιούµε τον πελάτη χρησιµοποιώντας συνιστώσες του SWING Μπορούµε να εµφανίσουµε τα ίδια στοιχεία µε διαφορετικούς τρόπους (thin/thick clients) Υλοποίηση ως ανεξάρτητη εφαρµογή Υλοποίηση ως Applet Χρήση HTML, Flash,...... Ο Πελάτης δεν γνωρίζει πως εκτελείτε η αίτηση Η υλοποίηση του επιπέδου µε RMI είναι (σαφώς) ποιο απλή από την αντίστοιχη που χρησιµοποιεί Sockets
import java.rmi.*; import java.awt.*; import java.awt.event.*; public class RemoteClient extends Frame { public static final String URL = "rmi://127.0.0.1/arserver"; ServerInterface theserver; Button thesearchflights = new Button("Search Flights");... TextField theflightno = new TextField();... TextArea theresults = new TextArea(); public static void main(string [] args) { new RemoteClient(); public RemoteClient() { super("airline Reservation System (Remote Client)... setsize(600, 400); setvisible(true); try { theserver = (ServerInterface) Naming.lookup(URL); catch (Exception ex) { ex.printstacktrace(); public void searchflights() throws Exception { theresults.settext(""); Flight [] flights = theserver.searchflights(); for (int i = 0; i < flights.length; i++) { theresults.append(flights[i] + "\n"); public void searchseats() throws Exception { theresults.settext(""); Reservation [] seats = theserver.searchseats(thepassengerno.gettext()); for (int i = 0; i < seats.length; i++) { theresults.append(seats[i] + "\n"); public void bookseat() throws Exception { theresults.settext(""); theserver.bookseat(theflightno.gettext(), thepassengerno.gettext(), thereservationno.gettext()); public void actionperformed(actionevent evt) { try { String cmd = evt.getactioncommand(); if (cmd.equals("search Flights")) searchflights(); else if (cmd.equals("search Seats")) searchseats(); else if (cmd.equals("book Seat")) bookseat(); catch (Exception ex) { ex.printstacktrace();
Εκτέλεση RMI Client package compute; import java.rmi.remote; import java.rmi.remoteexception; Εφόσον ο server τρέχει Ξεκινήστε τον Πελάτη: java RemoteClient public interface Compute extends Remote { <T> T executetask(task<t> t) throws RemoteException; public interface Task<T> { T execute(); package engine; public class ComputeEngine implements Compute { public ComputeEngine() { super(); public <T> T executetask(task<t> t) { return t.execute();... public static void main(string[] args) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); try { String name = "Compute"; Compute engine = new ComputeEngine(); Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, 0); Registry registry = LocateRegistry.getRegistry(); registry.rebind(name, stub); System.out.println("ComputeEngine bound"); catch (Exception e) { System.err.println("ComputeEngine exception:"); e.printstacktrace();
package client; public class ComputePi { public static void main(string args[]) { if (System.getSecurityManager() == null) { System.setSecurityManager(new SecurityManager()); try { String name = "Compute"; Registry reg = LocateRegistry.getRegistry(args[0]); Compute comp = (Compute) reg.lookup(name); Pi task = new Pi(Integer.parseInt(args[1])); BigDecimal pi = comp.executetask(task); System.out.println(pi); catch (Exception e) { System.err.println("ComputePi exception:"); e.printstacktrace(); package client; public class Pi implements Task<BigDecimal>, Serializable private static final long serialversionuid = 227L; /** constants used in pi computation */ private static final BigDecimal FOUR = BigDecimal.valueOf(4); /** rounding mode to use during pi computation */ private static final int roundingmode = BigDecimal.ROUND_HALF_EVEN; /** digits of precision after the decimal point */ private final int digits; /** * Construct a task to calculate pi to * the specified precision. */ public Pi(int digits) { this.digits = digits; /** * Calculate pi. */ public BigDecimal execute() { return computepi(digits); /** * Compute the value of pi to the specified number of * digits after the decimal point. The value is * computed using Machin s formula: * * pi/4 = 4*arctan(1/5) - arctan(1/239) * * and a power series expansion of arctan(x) to * sufficient precision. */ public static BigDecimal computepi(int digits) {...
/** * Compute the value, in radians, of the arctangent of * the inverse of the supplied integer to the specified * number of digits after the decimal point. The value * is computed using the power series expansion for the * arc tangent: * * arctan(x) = x - (xˆ3)/3 + (xˆ5)/5 - (xˆ7)/7 + * (xˆ9)/9... */ public static BigDecimal arctan(int inversex, int scale) {... > mkdir /public_html/classes > javac compute/compute.java compute/task.java > jar cvf compute.jar compute/*.class added manifest adding: compute/compute.class(in = 307) (out= 201)(deflat adding: compute/task.class(in = 217) (out= 149)(deflated > javac -cp /public_html/classes/compute.jar engine/computeengine.java > mkdir /public_html/classes/client > javac -cp /public_html/classes/compute.jar client/computepi.java client/pi.java > rmiregistry & > java -cp /src:/ /public_html/classes/compute.jar -Djava.rmi.server.codebase= http://zaphod/ beeblebrox/classes/compute.jar -Djava.rmi.server.hostname=zaphod -Djava.security.policy=server.policy engine.computeengine java -cp /src: /public_html/classes/compute.jar -Djava.rmi.server.codebase= http://ford/ perfect/classes/ -Djava.security.policy=client.policy client.computepi zaphod 45
Server Policy grant codebase "file:/home/beeblebrox/src/" { permission java.security.allpermission; ; Client Policy grant codebase "file:/home/perfect/src/" { permission java.security.allpermission; ; Σύνοψη 6 ης ιάλεξης Σύνοψη Φροντιστηρίου Κατανεµηµένα Συστήµατα ΙΙ Κατανεµηµένα Αντικείµενα Κύκλος Ζωής Ροή Εκτέλεσης Τεχνολογίες Υλοποίησης Ενδιάµεσα Λογισµικά Αντικειµενοστραφής Προγραµµατισµός σε JAVA Sockets Remote Method Invocation -- RMI Παράδειγµα RMI 1 Παράδειγµα RMI 2 Κατανεµηµένα Αντικείµενα Θέµατα Σχεδιασµού Αντικειµενοστραφής Προγραµµατισµός σε JAVA RMI Σύνοψη Μαθήµατος Σύνοψη Μαθήµατος Βιβλιογραφία Επόµενη ιάλεξη
Βιβλιογραφία Επόµενη ιάλεξη Βιβλίο Distributed Systems, Concepts and Design" (G.Coulouris, J.Dollimore, T.Kindberg) 1. Κεφάλαιο 5: Distributed Objects and Remote Invocation Βιβλίο Distributed Systems: Principles and Paradigms" (A.Tanenbaum, M.Steen) 1. Κεφάλαιο 2: Communication -- Μόνο 2.1, 2.2, 2.3 Βιβλίο Κατανεµηµένα Συστήµατα µε Java (Ι.Κ.Κάβουρας, Ι.Ζ.Μήλης, Γ.Β.Ξυλωµένος, Α.Α.Ρουκουνάκη) 1. Κεφάλαιο 16: Κατανεµηµένα αντικείµενα Trail: Custom Networking http://java.sun.com/docs/books/tutorial/rmi/ index.html Εµµένοντα Αντικείµενα Θέµατα Σχεδιασµού Αντικειµενοστραφής Προγραµµατισµός σε JAVA Hibernate