Internet Socket e RMI una breve introduzione alla programmazione in rete Chi sono? Come contattarmi? Matteo Baldoni Dipartimento di Informatica Università degli Studi di Torino Corso Svizzera, 185 I-10149 Torino (ITALY) Matteo Baldoni Dipartimento di Informatica Universita` degli Studi di Torino C.so Svizzera, 185 I-10149 Torino baldoni@di.unito.it http://www.di.unito.it/~baldoni/didattica e-mail: baldoni@di.unito.it URL: http://www.di.unito.it/~baldoni Tel.: +39 011 670 67 56 Fax.: +39 011 75 16 03 Pagina del corso: http://www.di.unito.it/~baldoni/didattica/ Sono nato a Torino nel 1968, nel febbraio 1993 mi sono laureato con lode in Scienze dell Informazione e nel febbraio 1998 sono diventato Dottore in Ricerca in Informatica. Dal luglio 1999 sono ricercatore in Informatica presso il Dipartimento di Informatica dell Università degli Studi di Torino. 2 Bibliografia Bibliografia Horstmann C. S. - Cornell G. Java 2 I fondamenti - seconda edizione, Mc Graw Hill, ISBN 88-386-4181-1, Giugno 2001, pp. 826 con CD-ROM (Euro 54,00) Java 2 tecniche avanzate, Mc Graw Hill, ISBN 88-386-4071-8, Aprile 2000, pp. 842 con CD- ROM (Euro 55,50) Eckel, B.Thinking in Java. Second Edition. Prentice-Hall Computer Books, 2000. ISBN: 0130273635 (anche online: http://www.bruceeckel.co m) Schimdt, D. Programming Principles in Java: Architectures and Interfaces. (On-line: http://www.cis.ksu.edu/~s chmidt/cis200/) 3 4 Bibliografia Architettura / Matteo Baldoni. Un introduzione al paradigma ad oggetti attraverso lo schema Kernel-Modulo. Rapporto Tecnico del Dip. Di Informatica e comparso nei numeri settembre, ottobre e novembre 2002 di Mokabyte (http://www.mokabyte.it) Un servizio presso un computer-server è identificato dai seguenti valori: IP (32 bit, presto 128 bit) (16 bit) Alcuni tipici servizi: telnet http ftp SMTP, IMAP4 NFS, DNS, NIS,... TCP Servizi telnet TCP ftp http IMAP TCP 5 6 1
Socket Socket e Stream in Java È una astrazione software che rappresenta il terminale di una connessione tra due computer Per ogni connessione esiste un socket in ognuno dei computer coinvolti Il client effettua la richiesta di una connessione ad un server per un servizio collegato ad una determinata porta Se la richiesta è accettata la connessione tra i due applicativi dei due computer è stabilita Socket: <IP,, IP, > TPC Socket: <IP,, IP, > 7 Da ogni socket è possibile ottenere uno stream di input ed uno di output L uso dei socket è trasparente: readline e println BufferedReader in = new BufferedReader( new InputStreamReader( socket.getinputstream())); PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getoutputstream())), true); Abilita il flush immediato 8 Socket in Java Socket () Package da importare java.net La classe java.net.socket implementa un client socket richiede l indirizzo IP e il numero della porta del servizio a cui vogliamo connetterci La classe java.net.socket implementa un server socket Socket richiede il numero della porta a cui vogliamo associare il servizio TPC crea un server che attende le richieste di connessione restituisce un socket nel momento in cui accetta un collegamento completamente istanziato nei Socket parametri di collegamento (IP e a locale e remota). 9 Socket socket = new Socket(IP, PORT); socket.close(); Crea una connessione con un applicazione server (in attesa in una accept()) e restituisce il relativo socket Le eccezioni che possono essere sollevate sono del tipo IOException (da catturare e gestire!) E`un valore intero, in genere non inferiore a 1024 (riservati al sistema) e rappresenta il numero della porta a cui Vogliamo connetterci E`un oggetto del tipo java.net.inetaddress contenente l indirizzo IP della macchina a cui vogliamo connetterci ad esempio speedy/130.192.241.1 Socket 10 Un esempio: connessione alla porta 80! import java.io.*; import java.net.*; public class SocketConnectionHTTP { BufferedReader in; PrintWriter out; Socket s; public SocketConnectionHTTP(String host, int port) throws IOException { s = new Socket(host, port); in = new BufferedReader( new InputStreamReader(s.getInputStream())); out = new PrintWriter(s.getOutputStream()); public SocketConnectionHTTP() throws IOException { this(console.readline("host: "), Console.readInt(": ")); Le prime 1024 porte sono in genere riservate a servizi di sistema (vedi /etc/services su unix) La porta 80 è riservata in genere al servizio di web server 11 Un esempio: connessione alla porta 80! public String getdocument(string document) throws IOException { String temp = ""; boolean more = true; La lettura e if (document==null) scrittura document = "/"; tramite un out.println ("GET "+ document + " HTTP/1.0 r n r n"); out.flush(); socket while (more) { avviene String line = in.readline(); if (line == null) come su un more = false; qualsiasi else temp += line + " n"; stream di IO In modo return temp; analogo è public String getdocument() throws IOException { possibile return getdocument(console.readline("document to get? ")); collegarsi public void close() throws IOException { alla porta 25 s.close(); per il servizo di posta 12 2
Astrazione: connessione URL import java.io.*; import java.net.*; public class URLConnectionTest { BufferedReader in; URLConnection s; public URLConnectionTest(String urlname) throws IOException { URL url = new URL(urlName); s = url.openconnection(); s.connect(); in = new BufferedReader( new InputStreamReader( s.getinputstream() )); public URLConnectionTest() throws IOException { this(console.readline("url: ")); Per effettuare delle connessioni sia ad un server di posta che ad un server web è possibile utilizzare delle classi che realizzano delle astrazioni sul tipo di protocollo utilizzato L uso dei socket è nascosto come quello del protocollo HTTP 13 Astrazione: connessione URL public String getdocument() throws IOException { int n = 1; String key; while ((key = s.getheaderfieldkey(n))!= null) { String value = s.getheaderfield(n); System.out.println(key + ": " + value); n++; System.out.println("----------"); System.out.println("getContentType: " + s.getcontenttype()); System.out.println("getContentLength: " + s.getcontentlength()); String temp = ""; boolean more = true; while (more) { String line = in.readline(); if (line == null) more = false; else temp += line + " n"; return temp; Per i server di posta esistono le classi del package JavaMail (package non incluso nella distribuzione standard) 14 Socket Il metodo accept() si mette in attesa di una richiesta di connessione da un socket client Le eccezioni che possono essere sollevate sono del tipo IOException (da catturare e gestire!) Socket Crea un nuovo socket sul server per Socket s = new Socket(PORT); accettazione di una richiesta di Socket socket = s.accept(); connessione System.out.println("Accettato socket " + socket); socket.close(); s.close(); Chiude il socket di una connessione precedentemente accettata Chiude il server 15 Socket e Socket: gestione errori E`importante che i socket siano propriamente chiusi al termine di un applicazione in quando questi sono una risorsa di rete condivisa del sistema La chiusura dei socket deve essere eseguita indipendentemente dal flusso di esecuzione per questo e`bene utilizzare il costrutto tryfinally per garantirne la chiusura La stessa considerazione vale anche per il Socket String str = in.readline(); out.println("offerta"); catch(ioexception e) { System.err.println("IO Exception" + e); finally { socket.close(); catch(ioexception e) { System.err.println("Socket not closed"); Socket socket = s.accept(); finally { s.close(); 16 Un esempio: l asta Un esempio: l asta Il server è il banditore: accoglie le offerte e comunica se sono accettabili o no, comunica a richiesta la migliore offerta corrente I client sono i partecipanti all asta, possono richiedere qual è la migliore offerta (e di chi) e possono effettuare rilanci se il loro budget a disposizione lo consente Un thread per ogni partecipante all asta L offerta è rappresentata da un oggetto che contine l offerente e l offerta in denaro La migliore offerta è memorizzata in un oggetto il cui accesso è effettuato mediante un metodo synchronized Per trasmettere un offerta è necessario convertirla in una stringa (encode) Il server ricostruisce dalla stringa ricevuta un offerta (decode) 17 18 3
Stream di oggetti e Socket Stream di oggetti e Socket Nell esempio dell asta i dati di una offerta venivano opportunamente codificati in una unica stringa per essere trasferiti da un client ad un server In Java si puo`pero` utilizzare anche stream di oggetti (ObjectInputStream e OutputObjectStream) In Java e`possibile utilizzare stream di oggetti tramite socket Gli oggetti devono implementare l interfaccia java.io.serializable Anche stream di oggetti TPC E` importante che possano essere serializzati 19 Socket s = new Socket(PORT); Socket socket = s.accept(); ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); Offerta nuova = (Offerta)in.readObject(); out.writeobject("accettata"); Importante: la dichiarazione nel client è analoga MA è l oggetto di tipo ObjectOutputStream va creato prima dell oggetto di tipo ObjectInputStream pena il deadlock (non è un bug!) 20 Polimorfismo via socket? Comunicazione distribuita TPC Gli oggetti trasmessi via stream di oggetti preservano il loro vero tipo A patto che il client (o il server) dispongano della loro definizione 1 Java VM1 Java VM2 2 Invocazione di metodi sull oggetto remoto 21 22 RMI: goal Rendere trasparente l invocazione remota di metodi su oggetti Java che risiedono su diverse Virtual machines (evoluzione di Remote Procedure Call, RPC) offrire un modello distribuito che preservi maggiormente la semantica degli oggetti Java rendere il piu semplice possibile la scrittura di applicazioni distribuite RMI è un ORB (Object Request Broker) ma non un CORBA (Common Object Request Broker Architecture) come stabilito dall OMG (Object Management Group) analogo a DCOM della Microsoft 23 Architettura RMI Supporta vari protocolli di invocazione: unicast, multicast Applicazione Livello Livello di riferimento remoto Applicazione Livello Livello di riferimento remoto Livello di Trasporto Rete Livello di Trasporto Si occupa della effettiva connessione, della identificazione degli oggetti remoti, del mezzo,, UDP (nota: RMI usa per ora solo ) Si occupa di preparare (marshalling) la remote call e gli oggetti per la trasmissione Ogni livello è indipendente dall altro! Skeleton per le versioni precedenti a Java 1.2 24 4
Architettura RMI RMI Il sistema RMI e` costituito da tre livelli per supportare flessibilità nella comunicazione Ogni livello ha le sue interfacce di comunicazione con relativi protocolli (e skeleton) layer: canale di comunicazione tra clients e server remote reference layer: supporto di diversi protocolli di invocazione tipo Unicast e Multicast transport layer: supporta la comunicazione a basso livello, tipo Simile all invocazione di metodi locali i parametri dei metodi possono essere oggetti il polimorfismo e` supportato: oggetti diversi possono rispondere a stessi messaggi ma i client interagiscono con interfacce di oggetti () non con la loro implementazione (che sta nella VM remota) parametri passati per copia, non per referenza (passaggio per referenza solo dentro a una VM) Distributed Garbage Collector (DGC) 25 26 RMI in pratica RMI in pratica: Interfaccia L oggetto blu sulla desidera inviare un messaggio all oggetto rosso sulla, gli oggetti giallo e azzurro fanno parte dei parametri del messaggio L oggetto rosso sulla terminata l esecuzione restituisce l oggetto verde come valore di ritorno oppure solleva un eccezione Il client deve disporre di un interfaccia che descriva l oggetto remoto È necessario che l interfaccia estenda java.rmi.remote Ogni metodo descritto puo` lanciare un eccezione di tipo java.rmi.remoteexception messaggio public interface Distributor extends java.rmi.remote { valore di ritorno o eccezione Job getnewjob() throws java.rmi.remoteexception; Job getnewjob(message msg) throws java.rmi.remoteexception; 27 28 RMI in pratica: Implementazione Il implementa la classe che esegue praticamente i metodi che sono descritti nell interfaccia remota Questa classe è necessario che estenda la classe java.rmi.server.unicastremoteobject (attualemente l unica disponibile, multicast in una futura versione) che rende accessibile le sue istanze remotamente (puo` creare uno per la classe) public class DistributorImpl extends java.rmi.server.unicastremoteobject implements Distributor { public Job getnewjob() throws java.rmi.remoteexception { 29 RMI in pratica: rmi, bind (rebind) Gli oggetti remoti sono individuati tramite un IP, un numero di porta e un nome (una stringa) server : processo pagine gialle Si registra l oggetto rosso presso il servizio di pagine gialle Non è necessario registrare l oggetto verde Naming.rebind Reference Layer: apertura di un server socket Lo è necessario durante il bind 30 5
RMI in pratica: rmi, bind (rebind) La classe Naming appartiene al package java.rmi rmi puo` anche essere attivato indipendentemente dal server tramite il comando rmi 2000 RMI in pratica: rmi, lookup Il client ottiene uno (surrogato dell oggetto rosso presso il client) tramite il server Deve conoscerne IP, porta e nome public DistributorImpl() throws RemoteException { porta java.rmi..locateregistry.createregistry(2000); Naming.rebind("rmi://127.0.0.1:2000/distributor",this); catch (Exception e) { System.err.println("Failed to bind to RMI Registry"); System.exit(1); IP address nome oggetto remoto Naming.lookup 31 32 RMI in pratica: rmi, lookup L oggetto remoto è contattato tramite il server È necessario conoscerne l indirizzo IP, il numero della porta e il nome con cui è registrato RMI in pratica: client L oggetto blu invia un messaggio al surrogato oggetto rosso presso lo client Lo client inizializza la chiamata remota ed organizza i parametri da inviare Garbage collector: mantiene un riferimento all oggetto rosso: non puo` essere eliminato public class { Distributor server; Tipo definito dall interfaccia! public () { server = (Distributor)Naming.lookup( "rmi://127.0.0.1:2000/distributor ); catch(exception e) { System.out.println("Failed to find distributor" + e.getmessage()); 33 messaggio L oggetto giallo e azzurro vengono serializzati e organizzati per la spedizione (marshalling) 34 RMI in pratica: invio messaggio L oggetto remoto è ora utilizzabile come un qualsiasi oggetto locale lo ne è un surrogato public class { public void process() { Job myjob = server.getnewjob(new Message("Richiesta Job!")); myjob.process(); catch (Exception e) { System.out.println("Failed to receive job " + e.getmessage()); 35 RMI in pratica: connessione Il livello di trasporto è responsabile per una connessione, nel server ascolta le richieste in arrivo mantiene la tabella degli oggetti remoti nel particolare address space Scambia le informazioni con il reference layer Anche HTTP se c è un firewall Il livello di trasporto apre un socket per la connessione Connessione temporanea! 36 6
RMI in pratica: server RMI in pratica: la risposta Lo server riorganizza i parametri (unmarshalling) individua l oggetto da chiamare attivando il metodo desiderato (informazione contenuta nel pacchetto ricevuto) Attenzione non vi è nessun riferimento agli oggetti giallo e azzurro sul client passati come parametro: sono copie! Lo del server cattura e riorganizza il valore restituito dall evecuzione del metodo sull oggetto rosso Lo server invia allo del client un pacchetto contenente le informazioni raccolte (l oggetto verde) Invia valore di ritorno o eccezione 37 38 RMI in pratica: la risposta RMI in pratica: ricezione Il server esegue il metodo invocato ed invia il valore di ritorno come se la chiamata fosse locale Lo client riorganizza le informazioni ricevute o l eccezione sollevata La connessione viene quindi disattivata public DistributorImpl() throws RemoteException { public Job getnewjob(message msg) { System.out.println(msg); if( count < jobs.size()) { return (Job)jobs.elementAt(count++); else { System.exit(0); return null; 39 40 RMI in pratica: ricezione RMI: riassunto Il valore di ritorno è utilizzato come se fosse ora un oggetto locale ma non ha nessun riferimento con quello creato sul server (come per i parametri inviati con la chiamata) public class { public void process() { Job myjob = server.getnewjob(new Message("Richiesta Job!")); myjob.process(); catch (Exception e) { System.out.println("Failed to receive job " + e.getmessage()); 41 Nell esempio che vedremo: javac *.java rmic -v1.2 DistributorImpl rmi 2000 & java DistributorImpl java Esegue il client Attiva il server Dopo in bind è attivo un thread separato per gestire le richieste di connessione, termina con CTRL-C Crea il file: DistributorImpl_Stub.class Senza l opzione viene creato anche il file DistributorImpl_Skel.class compatibile sia con Java 1.1 e 1.2 Attiva il server 42 7
RMI: download dello Lo generato dal server deve essere disponibile al client ma questo, in genere, è remoto Puo` essere scaricato tramite HTTP download HTTP Web java.rmi.server.codebase property La proprieta` codebase indica dove cercare una classe remotamente È l analogo del CLASSPATH Protocolli: file, ftp, o http Web L informazione del codebase è memorizzata Naming.rebind nel file di criteri Security Manager 43 Il server viene avviato specificando la proprieta` codebase java -Djava.rmi.server.codebase=http://Host/dirctory/ 44 RMI: security manager RMI: security manager RMISecurityManager con l associato file di criteri permette di scaricare mediante il protocollo HTTP È necessario un file di criteri public class { Distributor server; public () { System.setSecurityManager(new RMISecurityManager()); server = (Distributor)Naming.lookup( "rmi://127.0.0.1:2000/distributor ); catch(exception e) { System.out.println("Failed to find distributor" + e.getmessage()); 45 Per utilizzare il file di criteri nel client: java -Djava.security.policy=client.policy Per indicare da dove scaricare il file dal server: java -Djava.rmi.server.codebase=http://127.0.0.1:8080/ DistributorImpl file client.policy grant { permission java.net.socketpermission 127.0.0.1:1024-65535", "connect"; ; grant { permission java.security.allpermission; ; in alternativa: da usare solo per test 46 L utilita` policytool http deamon con tools.jar JDK contiene uno strumento (molto semplice) che consente la modifica dei file di criteri (o politiche) Non di facile utilizzo se non si conosce gia` come specificare le autorizzazioni Per effettuare test è possibile utilizzare il package tools.jar dal progetto JINI All avvio viene attivato un demone http sulla porta specificata dall opzione -port che pubblica il direttorio specificato dall apzione -dir L opzione -verbose visualizza su console l attivita` del demone http java -jar tools.jar -port PORTA -dir DIRECTORY -verbose 47 48 8
RMI: polimorfismo L oggetto inviati tramite RMI preservano il loro vero tipo Ma se il valore restituito è piu` specializzato di quello atteso dal client che succede? Download delle classi per trattare l oggetto specializzato! file di criteri Security Manager download HTTP Web 49 RMI: polimorfismo E se l oggetto inviato come parametro è piu` specializzato di quello atteso dal server? Download delle classi via HTTP durante l esecuzione del metodo sull oggetto remoto (sul server) Il server necessita a sua volta di un Security Manager per il controllo delle classi scaricate È nececessario un file di criteri per il download anche per il server Il client deve specificare dove scaricare le classi 50 RMI: polimorfismo Web HTTP download download HTTP Web file di criteri file di criteri Security Manager 51 9