Organizzazione della lezione 18. Applicazioni ed Esempi (2) Vittorio Scarano Corso di Programmazione Distribuita Laurea di I livello in Informatica Università degli Studi di Salerno Organizzazione della II prova intercorso ed esami Il problema dell accesso al registry per il Una soluzione con registry multipli Alcuni commenti finali 2 II prova intercorso Prove scritte degli esami successivi Fissata il 29 gennaio 2003, ore 15, aula D-19 Struttura: una applicazione distribuita usando Java RMI Durata: 3 ore Orali: nella settimana successiva all esame orale, si richiederà anche la presentazione del programma della prova scritta, funzionante e con il minimo numero di modifiche rispetto alla versione consegnata necessario: listato completo del programma funzionante e commentato dischetto (esente da virus) con i programmi pronti per poter essere compilati ed eseguiti Febbraio: 10/2/2003, ore 9 (C-38), 25/2/2003, ore 9 (D-19) La prova scritta (durata 3 ore) sarà simile alla unione delle due prove intercorso 5-6 domande su Java da 2 punti 1-2 domande di programmazione Java (da 12 punti) la applicazione distribuita (Java RMI) da scrivere Orali: nella settimana successiva alla prova scritta 3 all esame orale, si richiederà anche la presentazione del programma della prova scritta, funzionante e con il minimo numero di modifiche rispetto alla versione consegnata necessario: listato completo del programma funzionante e commentato dischetto (esente da virus) con i programmi pronti per poter essere compilati ed eseguiti 4
L accesso al registry per il Una chat client-server (con callback) Il problema: Il server su un registry che si trova su un host diverso dalla JVM si può fare e list() ma non si può fare la bind(),! Esaminiamo le architetture delle applicazioni chat Chat client-server (con call-back) Chat peer-to-peer 5 riceve da ogni client la iscrizione/abbandono della chat manda a tutti i client quello che ognuno dice (broadcast) Meccanismo mediante il quale il client chiede al server di essere richiamato (call-back) con RMI il client (dotato di interface remota) passa il proprio riferimento remoto al server che lo usa per contattarlo successivamente necessità del call-back implicita nella applicazione: il server deve poter informare ogni client di quanto digitato da un client permette ad ogni utente di avere la informazione su chi è iscritto alla chat 6 Le classi di Chat Client-Server Server.java import java.rmi.*; public interface Server extends java.rmi.remote { public void dico (Messaggio m) public void iscrivi (Remote idref) public void abbandona (Remote idref) Tre metodi remoti dico() chiamato da un client se deve scrivere a tutti iscrizione alla chat abbandona() per abbandonare Passaggio del riferimento remoto necessario per il callback 7 8
Le classi di Chat Client-Server Chat.java import java.rmi.*; public interface Chat extends java.rmi.remote { public void dico (Messaggio m) public void iscrivi (String nickiscritto) public void abbandona (String nickabbandona) public String getnickname () Interfaccia remota Quattro metodi remoti dico() chiamato dal server per il broadcast di messaggi, abbandona() consapevolezza della iscrizione/abbondono alla chat di un utente getnickname() utilità per uso da parte del server (non fondamentale) Metodi chiamati solo dal server 9 10 La Chat Client-Server Server: : architettura (1) La Chat Client-Server Server: : architettura (2) Set-up del server Iscrizione di un client ClientDue Iscrizione di un client Server ServerChat notare che non servono registry per arrivare a e ClientDue.. infatti ClientDue RemRef ServerChat ClientDue 11 12
La Chat Client-Server Server: : architettura (3) Commenti sulla architettura della Chat Per il call-back il server usa i riferimenti remoti che ha La architettura Client-Server della Chat e che sono stati comunicati con ClientDue dico( Ciao ) RemRef ServerChat dico( Ciao ) ClientDue dico( Ciao ) offre un singolo punto di debolezza (il server) non risponde alla struttura del problema in effetti, ogni client deve poter inviare a ciascun altro client serve solamente poter sapere chi sono i client registrati Possibile passare ad una architettura Peer-to-peer dove l unica componente centralizzata è il registry che deve necessariamente essere presente (comunque) anche sulla architettura client-server 13 14 Il ruolo del registry nelle applicazioni P2P Le classi di Chat P2P Per ogni applicazioni peer-to-peer è comunque sempre necessario una componente che permetta il bootstrap: locazione fissata per poter contattare gli altri peer Nel caso di RMI si può usare il registry tramite il metodo list() è possibile sapere tutti gli id (stringhe) degli oggetti remoti registrati a partire da cui si può ottenere il riferimento remoto che può essere usato per contattare gli oggetti (discriminando, se è il caso, rispetto alle interface implementate) se sul registry stanno in esecuzione diverse applicazioni distribuite 15 16
Chat.java Alcuni commenti sulla Chat import java.rmi.*; public interface Chat extends java.rmi.remote { public void dico (Messaggio m) public void iscrivi (String id) public void abbandona (Remote idref) public String getnickname () Interfaccia remota Quattro metodi remoti dico() chiamato da un altro peer per scrivere un messaggio, abbandona() inserimento o cancellazione nella lista dei peers che ognuno ha getnickname() utilità per uso da parte degli altri peers (non fondamentale) 17 Applicazione peer-to-peer peer di dimensione maggiore rispetto al client della soluzione client-server non soggetta a fault-locali in caso il registry cada, chi è connesso continua a chattare fino alla chiusura (partial faults tolerance) Un problema: su un registry che si trova su un host diverso dalla JVM si può fare e list() ma non si può fare la bind(),! con questa implementazione si può fare una chat solo se ci si 18 trova sullo stesso host (stesso registry!) Il problema della Chat P2P su host diversi La Chat P2P (2) sullo stesso host Iscrizione di un peer Iscrizione di un peer : al registry ok, a ok, su registry fallisce! Iscrizione di un peer Iscrizione di un peer : al registry ok, a ok, ok! 19 20
Una soluzione: ChatMultipleRegistry Le classi di ChatMultipleRegistry (identiche) L idea: ogni peer ha una lista di host su cui si potrebbero trovare dei peer che partecipano alla chat per ogni host nella lista controlla se esiste un registry se esiste il registry, preleva la lista dei nomi chiede i riferimenti remoti si registra sul proprio registry Da notare: ogni registry può servire più oggetti Chat 21 22 ChatImpl.java: main() () (1) ChatImpl.java: main() () (2) import java.io.*; import java.rmi.*; import java.rmi.server.*; import java.util.*; public class ChatImpl extends UnicastRemoteObject implements Chat { public static void main(string args[]) { if (args.length > 0 ) nickname = args[0]; else { System.out.println ( Serve nickname"); System.exit(1); System.setSecurityManager( new RMISecurityManager()); // continua Identico al precedente 23 try { ArrayList nomi = new ArrayList(); String n[] ; for (int i = 0; i < HOST.length; i++) { n=null; try { n = Naming.list("rmi://"+HOST[i]); catch (ConnectException e) { System.out.println(HOST[i]+ " non presente.."); if (n!= null) for (int j=0; j < n.length; j++) nomi.add(n[j]); System.out.println ("Risultano connessi "+ nomi.size()+" utenti:"); for (int i=0 ; i < nomi.size(); i++) System.out.println ("\t"+nomi.get(i)); // continua Ottiene l elenco dei nomi da tutti i registry presenti preleva la lista da ogni registry se genera una eccezione continua se n[] riferisce ad un array: esiste il registry.. e allora si inseriscono i nomi nell array di nomi[] Stampa le informazioni 24
ChatImpl.java: main() () (3) ChatImpl.java: : (unico altra differenza) for (int i=0 ; i < nomi.size(); i++) peers.add(naming.lookup ( (String) nomi.get(i))); ChatImpl myself = new ChatImpl(); Naming.rebind(nickname, myself); System.out.println ( Iscrizione ai peers:"); for (int i=0 ; i < peers.size(); i++) { System.out.print ("\tiscrizione a "+((Chat) peers.get (i)).getnickname()+".."); ((Chat) peers.get (i)).iscrivi (nickname) ; System.out.println ("effettuata!"); catch (Exception e) { System.out.println("Eccezione"); e.printstacktrace(); // resto del main (Shell) identico a Chat P2P Riferimenti remoti ogni nome prelevato dal registry contiene le informazione sul registry rmi://10.0.0.24:1099/pippo Registrazione sul proprio registry solo con il nickname usa localhost Iscrizione presso gli altri peer: chiamata di 25 public void iscrivi (String id) throws RemoteException { try {String n[]; Remote ref; for (int i = 0; i < HOST.length; i++) { ref = null; try { ref = Naming.lookup( "rmi://"+host[i]+"/"+id); catch (RemoteException e) { if (ref!= null) {// trovato! peers.add(naming.lookup ( "rmi://"+host[i]+"/"+id)); break; //esce dal for //end for catch (Exception e) { System.out.println ("Id non presente?"); e.printstacktrace(); System.out.print ("\nentra "+id+"\n"+prompt); Il metodo remoto riceve una id (stringa) e adesso deve cercare su tutti i registry! Cerca la id sugli host ignora eccezioni da qui: o niente registry sull host o niente id sul registry Se la trovo aggiungo alla lista dei peer il riferimento remoto esco dal for Stampo il prompt 26 ChatImpl.java: ultime differenze Chat P2P con Multiple Registry //Altri metodi e variabili identici a ChatImpl P2P //Definizione dell elenco di host public static final String[ ] HOST = { "10.0.0.99", "10.0.0.1", "10.0.0.137", "10.0.0.201 ; //fine classe ChatImpl La costante HOST qui è un array di stringhe Attenzione: il localhost deve essere incluso all interno della lista di indirizzi nell array HOST Ovviamente: la lista di host può essere prelevata da un server in questo modo il peer diventa client (solo per la lista) in una architettura client-server 27 Iscrizione di peers su due host, e PeerTre PeerTre PeerTre PeerTre 28
Commenti sulle architetture proposte (1) La race condition (1) Un commento generale: qualsiasi sistema peer-to-peer deve dipendere da qualche entità esterna (server?) per il bootstrap Le scarne soluzioni proposte sono a scopo didattico: tra le altre cose, non coprono: nickname duplicati sovrascrivono senza pietà riferimenti se più utenti hanno la stessa situazioni di malfunzionamenti parziali (catch da completare) caduta di un registry durante la chat problemi di race condition due client che si connettono contemporaneamente allo stesso registry ma le cui operazioni di e rebind sono mischiate (interleaved) 29 La situazione come dovrebbe essere funziona tutto 30 La race condition (2) Una soluzione alla race condition La situazione come potrebbe essere con la legge di Murphy se una cosa può andare storta, lo farà! Prevedere di fare il prima della iscrizione a tutti i nodi reperiti: in questa maniera, però, è necessario: controllare che le invocazioni di che arrivano a un nodo non siano di nodi che già abbiamo nel nostro array di peers controllare di non effettuare alcuna chiamata remota a sé stessi controllando che il riferimento di cui si vuole invocare il metodo remoto (chiamando il metodo o il metodo abbandona()) sia diverso dal proprio riferimento oppure controllando che il riferimento da inserire nell arraylist peers sia diverso dal proprio 31 32
Come funziona questa soluzione La race condition (3): Soluzione Si fa il prima di cercare altri nodi Funzionamento senza problemi di race condition i riferimenti in blu sono auto-riferimenti ed è necessario non effettuare chiamate remote (abbandona(),, dico() etc.) oppure non inserirlo nell array peers Si fa il prima di cercare altri nodi Un ulteriore controllo da effettuare: ricezione di da nodi già in peers No. Già presente! 33 34 Conclusioni del corso Il corso è basato su: il linguaggio Java testo: Horstmann una tecnologia per le invocazioni remote (Java RMI) testo: Specifiche del linguaggio della Sun modelli e architetture distribuite testo: Couloris applicazioni ad applicazioni distribuite esempi a lezione Una avvertenza ( studenti avvisati, mezzi salvati ) studiare dai lucidi è assolutamente insufficiente E previsto un corso complementare (laurea di II livello) di Programmazione Distribuita Avanzata (titolo provvisorio) l anno prossimo dove si completerà lo studio con altre tecnologie: Jini, JXTA, Enterprise JavaBeans, etc. 35