Università degli Studi di Pisa Dipartimento di Informatica Lezione n.6 LPR Informatica Applicata Serializzazione JAVA (alcuni lucidi sono ripresi da appunti di Leonardo Puleggi) 28/03/2013 Laura Ricci Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 1 SERIALIZZAZIONE • in JAVA, ogni entità è rappresentata come un oggetto; se due entità vogliono comunicare si devono scambiare oggetti • serializzazione: meccanismo che permette di salvare un oggetto o un grafo di oggetti su uno stream di byte che successivamente può essere salvato su un file inviato sulla rete • deserializzazione: processo inverso, permette di ricostruire l'oggetto/il grafo di oggetti dallo stream di byte • La serializzazione si basa sulla possibilità di scrivere lo stato di un oggetto in una forma sequenziale, sufficiente per ricostruire l'oggetto quando viene riletto. Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 2 SERIALIZZAZIONE La serializzazione di oggetti viene usata in diversi contesti: inviare oggetti su uno stream che rappresenta una connessioneTCP flattening di oggetti: trasformare un oggetto in un array Utilizzato per costruire pacchetti UDP. di byte. inviare oggetti che sono parametri di metodi invocati via RMI fornire un meccanismo di persistenza ai programmi, consentendo l'archiviazione di un oggetto. ● esempio: un programma che realizza una rubrica telefonica o un'agenda. Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 3 JAVA: LA SERIALIZZAZIONE • Meccanismo standard offerto da JAVA Le classi ObjectInputStream e ObjectOutputStream definiscono streams (basati su streams di byte) su cui si possono leggere e scrivere oggetti. per rendere un oggetto “persistente”, l'oggetto deve implementare l'interfaccia Serializable o ereditarne una implementazione dalla gerarchia di oggetti. l'oggetto e tutti i suoi componenti debbono essere serializzabili non tutti gli oggetti possono essere serializzati. Es: oggetti del sistema quali Thread, OutputStream e Socket non possono essere serializzate • Altri meccanismi offerti da JAVA personalizzare il meccanismo di default (interfaccia Serializable) creare un proprio protocollo (classe Externalizable) Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 4 JAVA: LA SERIALIZZAZIONE In rosso le parti relative alla serializzazione import java.io.Serializable; import java.util.Date; import java.util.Calendar; public class PersistentTime implements Serializable { private static final long serialversionUId=1; private Date time; public PersistentTime() {time = Calendar.getInstance().getTime(); } public Date getTime() {return time; } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 5 JAVA: LA SERIALIZZAZIONE import java.io.*; public class FlettenTime {public static void main(String [] args) {String filename = "time.ser"; if(args.length > 0) { filename = args[0]; } PersistentTime time = new PersistentTime(); FileOutputStream fos = null; ObjectOutputStream out = null; try { fos = new FileOutputStream(filename); out = new ObjectOutputStream(fos); out.writeObject(time); out.close(); } catch(IOException ex) {ex.printStackTrace();}}} Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 6 JAVA: LA SERIALIZZAZIONE public class InflateTime {public static void main(String [] args) {String filename = "time.ser"; if(args.length > 0) {filename = args[0]; } PersistentTime time = null; FileInputStream fis = null; ObjectInputStream in = null; try {fis = new FileInputStream(filename); in = new ObjectInputStream(fis); time = (PersistentTime)in.readObject(); in.close(); } catch(IOException ex){ ex.printStackTrace(); } catch(ClassNotFoundException ex) {ex.printStackTrace();} Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 7 JAVA: LA SERIALIZZAZIONE // print out restored time System.out.println("Flattened time: " + time.getTime()); System.out.println(); // print out the current time System.out.println("Current time: "+ Calendar.getInstance().getTime());} } Output ottenuto: Flattened time: Mon Mar 12 19:11:55 CET 2012 Current time: Mon Mar 12 19:16:24 CET 2012 ClassNotFoundException: l'applicazione tenta di caricare una classe, ma non trova nessuna definizione di una classe con quel nome Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 8 JAVA: LA SERIALIZZAZIONE • La versione viene utilizzata in fase di deserializzazione per verificare che le classi utilizzate da chi ha serializzato l'oggetto e da chi lo sta deserializzando siano compatibili (vedere second aparte della lezione) • Il metodo ObjectInputStream.readObject() legge la sequenza di bytes memorizzati in precedenza e crea un oggetto che è l'esatta replica di quello originale • Poichè readObject può leggere qualsiasi tipo di oggetto, è necessario effettuare un cast al tipo corretto dell'oggetto • Il file con la specifica della classe deve essere accessibile quando si ricostruisce l'oggetto, altrimenti viene sollevata una ClassNotFoundException Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 9 SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI import java.io.Serializable; import java.util.*; public class Padre implements Serializable { private static final long serialVersionUID = 1L; private String nome; private String cognome; private Collection<Figlio> figli; public Padre(String nome,String cognome){ this.nome=nome; this.cognome=cognome; figli=new ArrayList<Figlio>(); } public void aggiungiFiglio(Figlio f){ figli.add(f); } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 10 SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI public String toString(){ StringBuilder temp=new StringBuilder("Padre"); temp.append("\n"); temp.append("nome: "); temp.append(this.nome); temp.append("\n"); temp.append("cognome: "); temp.append(this.cognome); emp.append("\n"); temp.append("Figli: "); temp.append(figli.toString()); return temp.toString(); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 11 SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI import java.io.Serializable; public class Figlio implements Serializable{ private static final long serialVersionUID = 1L; private String nome; private String cognome; public Figlio(String nome,String cognome){ this.nome=nome; this.cognome=cognome; } public String toString(){ return "nome: "+nome+" cognome: "+cognome; } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 12 SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI public class SerializzaPadre { public static void main(String[] args) { Figlio a=new Figlio("mario","rossi"); Figlio b=new Figlio("maria","rossi"); Padre p=new Padre("giovanni","rosso"); p.aggiungiFiglio(a); p.aggiungiFiglio(b); ObjectOutputStream output=null; try{ output=new ObjectOutputStream(new FileOutputStream("dati.dat")); } catch (FileNotFoundException e) { System.out.println("Impossibile trovare il file "); e.printStackTrace(); System.exit(1); } catch(IOException ioe){ System.out.println("Errore IO"); ioe.printStackTrace(); System.exit(1); } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 13 SERIALIZZAZIONE: GRAFO DEI RIFERIMENTI try { output.writeObject(p); } catch (IOException e1) { System.out.println("Impossibile serializzare l'oggetto " + p); e1.printStackTrace(); System.exit(1); } try { output.close(); } catch (IOException e2) { System.out.println("Impossibile chiudere lo stream "); e2.printStackTrace(); } System.out.println("Serializzazione completata."); }} Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 14 DESERIALIZZAZIONE: GRAFO DEI RIFERIMENTI import java.io.*; public class DeSerializzaPadre { public static void main(String[] args) { ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream("dati.dat")); } catch (FileNotFoundException e) { System.out.println("Impossibile trovare il file "); e.printStackTrace(); System.exit(1);} catch (IOException e) { System.out.println("Errore nella creazione dello stream "); e.printStackTrace(); System.exit(1); } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 15 DESERIALIZZAZIONE: GRAFO DEI RIFERIMENTI Padre p=null; try { p = (Padre) ois.readObject(); } catch (IOException e1) { System.out.println("Errore nella creazione dello stream "); e1.printStackTrace(); System.exit(1); } catch (ClassNotFoundException e1) { System.out.println("Impossibile trovare la classe"); e1.printStackTrace(); System.exit(1); } System.out.println(p.toString()); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 16 SERIALIZZAZIONE • L'esempio precedente mostra che si possono serializzare/deserializzare oggetti che al loro interno fanno riferimento ad altri oggetti • L'implementazione serializza transitivamente tutti gli oggetti riferiti • Se però uno degli oggetti riferiti non è serializzabile, viene sollevata una NotSerializableException • E' possibile non includere il valore di alcuni attributi nell'oggetto serializzato, mediante l'utilizzo della parola chiave transient Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 17 SERIALIZZAZIONE import java.io.Serializable; import java.util.*; public class Padre implements Serializable { private static final long serialVersionUID = 1L; private String nome; private String cognome; transient private Collection<Figlio> figli; …..... Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 18 SERIALIZZAZIONE • l'attributo transient inserito nell'esempio precedente indica che non si vuole serializzare l'attributo Figli della classe Padre • la parola chiave transient limita la visita nell'albero dei riferimenti • tutti gli altri attributi vengono salvati • se si esegue la serializzazione e quindi la deserializzazione, il campo figli nell'oggetto deserializzato, risulta uguale a null Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 19 LA SERIALIZZAZIONE STEP BY STEP Cosa avviene quando un oggetto viene serializzato? Si registrano sullo stream: • i “magic data” • I metadati che descrivono la classe associata alla istanza dell'oggetto serializzato (La classe Padre nell'esempio precedente) STREAM_MAGIC = “acde” STREAM_VERSION = versione della JVM La descrizione include il nome della classe, il serialVersionUID della classe, il numero di campi, altri flag. • • I metadati di eventuali superclassi, fino a raggiungere java.lang.Object • I dati degli oggetti eventualmente riferiti dall'oggetto istanza della classe, iniziando dai metadati e poi registrando i valori. (Le istanze della classe Figlio, nell'esempio precedente). • Non si registrano i metodi della classe I valori associati all'oggetto istanza della classe, partendo dalla super classe top most Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 20 LA SERIALIZZAZIONE STEP BY STEP • • Consideriamo la classe SimpleClass con campi firstName, lastName, weight Location L'oggetto istanza della classe contiene i campi {"Brad","Pitt",180.5, {49.345, 67.567}} • A fianco:risultato della serializzazione • Notare: per la memorizzazione di un oggetto di 20 bytes utilizzati circa 220 bytes Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 21 LA SERIALIZZAZIONE: “UNDER THE HOOD” Meccanismi implementati dalla JVM che è importante conoscere per utilizzare la serializzazione in modo corretto: Caching Controllo delle versioni Deadlock Performance Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 22 SERIALIZATION CACHE public class BigData { private static final long TERA_BYTE = 1024L * 1024 * 1024 * 1024; public static void main(String[] args) throws IOException { long bytesWritten = 0; byte[] data = new byte[100 * 1024 * 1024]; ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("bigdata.bin") ) ); long time = System.currentTimeMillis(); Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 23 SERIALIZATION CACHE for (int i = 0; i < 10 * 1024 * 1024; i++) { out.writeObject(data); bytesWritten += data.length; } out.writeObject(null); out.close(); time = System.currentTimeMillis() - time; System.out.printf("Wrote %d TB%n", bytesWritten / TERA_BYTE); System.out.println("time = " + time); } } Wrote 1000 TB Time = 3693 Ma la dimensione del file bigdata.bin è solo di 150 M. Come è possibile??? Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 24 SERIALIZATION CACHE • Ogni qual volta un oggetto viene serializzato e inviato ad una ObjectOutputStream, la sua identità viene memorizzata in una “identity hash table” • Se l'oggetto viene scritto nuovamente sull'OutputStream, l'oggetto stesso non viene nuovamente serializzato, ma viene memorizzato un puntatore all'oggetto serializzato in precedenza scopo: minimizzazione delle scritture e risoluzione di relazioni circolari tra oggetti • • Comportamento analogo quando si legge da uno stream: l'oggetto letto viene memorizzato in una “identity hash table”, la prima volta Letture future fanno riferimento allo stesso oggetto Possibili inconsistenze quando lo stato dell'oggetto viene modificato La modifica viene persa sull'ObjectOutputStream, perchè non viene aggiornato lo stato Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 25 SERIALIZZAZIONE: BUFFERIZZAZIONE Un esempio che dimostra i problemi che può dare un serialization cache: import java.io.*; public class MyObject implements Serializable{ private static final long serialVersionUID = 1L; private int x; public MyObject(){ }; public void set( int x) {this.x=x;} public int get() {return x;}; } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 26 SERIALIZZAZIONE: BUFFERIZZAZIONE import java.io.*; import java.net.*; public class SerializationClient { public static void main (String Args [] ) throws Exception { Socket s= new Socket("localHost",4000); ObjectOutputStream out = new ObjectOutputStream (s.getOutputStream()); MyObject myobj = new MyObject(); myobj.set(100); out.writeObject(myobj); myobj.set(200); out.writeObject(myobj); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 27 SERIALIZZAZIONE: BUFFERIZZAZIONE import java.net.*; import java.io.*; public class SerializableServer { public static void main(String args[]) throws Exception {ServerSocket ss = new ServerSocket(4000); Socket s=ss.accept(); ObjectInputStream ois= new ObjectInputStream (s.getInputStream()); MyObject myobj = (MyObject)ois.readObject(); System.out.println(myobj.get()); myobj = (MyObject)ois.readObject(); System.out.println(myobj.get()); OUTPUT 100 100 }} Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 28 SERIALIZZAZIONE: CACHING import java.io.*; import java.util.Arrays; public class FillCache { public static void main(String[] args) throws IOException { byte[] data = new byte[10 * 1024 * 1024]; ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("smalldata.bin") ) ); for (int i = -128; i < 128; i++) { Arrays.fill(data, (byte) i); out.writeObject(data); } out.writeObject(null); out.close(); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 29 SERIALIZZAZIONE: CACHING import java.io.*; public class ReadCache { public static void main(String[] args) throws Exception { ObjectInputStream in = new ObjectInputStream( new BufferedInputStream( new FileInputStream("smalldata.bin") ) ); byte[] data; while ((data = (byte[]) in.readObject()) != null) { System.out.println(data[0]); } in.close(); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 30 SERIALIZZAZIONE: CACHING • La stampa ottenuta: -128, -128, -128, ….. • Perdita di valori dovuta al meccanismo di serializzazione • Al momento della deserializzazione, si legge il vettore contenente 128 la prima volta e si memorizza nella “identity hash table” • Quando legge un puntatore all'oggetto, si ricerca il valore dell'oggetto dalla cache locale • Il meccanismo di serializzazione ignora se l'oggetto è stato modificato Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 31 SERIALIZZAZIONE: CACHING import java.io.*; import java.util.Arrays; public class FillCache1 { public static void main(String[] args) throws IOException { ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("verylargedata.bin"))); for (int i = -128; i < 128; i++) { byte[] data = new byte[10 * 1024 * 1024]; Arrays.fill(data, (byte) i); out.writeObject(data); } out.writeObject(null); out.close(); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 32 SERIALIZZAZIONE: CACHING Risultato ottenuto Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at FillCache1.main(FillCache1.java:13) Il file generato è di dimensioni molto grandi Ogni volta che un oggetto viene scritto sullo stream, esso viene posto nella “identity hash table” Rimane nella table finchè non viene effettuata una reset sullo stream Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 33 SERIALIZZAZIONE: CACHING import java.io.*; import java.util.Arrays; public class FillCache2 { public static void main(String[] args) throws IOException { ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream("verylargedata.bin")) ); byte[] data = new byte[10 * 1024 * 1024]; for (int i = -128; i < 128; i++) { Arrays.fill(data, (byte) i); out.writeObject(data); out.reset(); } out.writeObject(null); out.close(); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 34 SERIALIZZAZIONE: CACHING • La stampa ottenuta -128, -127, -126, … • Il programma non segnala un OutOfMemory Error • La reset effettua il flush della tabella dopo ogni operazione di scrittura • Ad ogni write un nuovo oggetto sullo stream • Svantaggio: nessuna ottimizzazione, tutti i valori(anche i campi che non hanno cambiato valore) eliminati dalla cache • Infatti il programma richiede molto tempo per terminare Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 35 IL CONTROLLO DELLE VERSIONI • supponiamo di creare una classe i cui oggetti siano serializzabili • serializziamo un oggetto istanza di quella classe • problema: se cambio la specifica della classe, possono le istanze serializzate secondo la vecchia specifica essere deserializzate come istanze della nuova classe? in generale questo non è possibile • meccanismo di controllo delle versioni ad ogni classe serializzabile viene attribuito un identificatore unico, il SerialVersionUID Tale identificatore viene rigenerato ogni volta che viene modificata la classe Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 36 IL CONTROLLO DELLE VERSIONI • Il serialVersionUID viene generato a partire dal codice della classe • Modificando il codice si modifica il serialVersionUID • Generato al momento di una serializzazione/deserializzazione • Quando deserializzo, se ho modificato il codice, la deserializzazione fallisce si tenta di rileggere l'oggetto, la ricostruzione dell'oggetto fallisce e viene sollevata una java.io.InvalidClassException Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 37 IL CONTROLLO DELLE VERSIONI • SerialVersionUID utilizzato in fase di deserializzazione per verificare che il mittente ed il destinatario di un oggetto serializzato fanno riferimento a classi compatibili • Le classi in realtà potrebbero essere compatibili • Possibile, in questo caso, specificare esplicitamente il serialVersionUID e forzarlo uguale nelle due versioni • Specifica serialVersionUID: il valore può essere qualsiasi valore long private static final long serialVersionUID = 3487495895819393L; Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 38 IL CONTROLLO DELLE VERSIONI • Specifica serialVersionUID: il valore può essere qualsiasi valore long private static final long serialVersionUID = 3487495895819393L; • Il meccanismo di serializzazione controlla se l'utente ha dichiarato esplicitamente un valore per il serialVerisonUID ed, in questo caso, usa questo valore, invece di calcolarlo in modo automatico • Se in una classe non esiste una dichiarazione esplicita di un serialVersionUID, il meccanismo di serializzazione lo calcola automaticamente • Dichiarazione esplicita di serialVersionUID: per garantire valori consistenti tra diverse implemetazioni di compilatori JAVA Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 39 CONTROLLO DELLE VERSIONI • L'identificatore della classe in Eclipse puntando il mouse sul nome di una classe Serializzabile appare una finestra che SerialVersionID Dipartimento di Informatica Università degli studi di Pisa permette di generare JAVA Serializzation automaticamente Laura Ricci un 40 CONTROLLO DELLE VERSIONI • L'identificatore della classe in Eclipse puntando il mouse sul nome di una classe Serializzabile appare una finestra che SerialVersionID permette di generare automaticamente un utilizzando add generated serial version ID Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 41 OBJECT STREAM: DEADLOCK • Supponiamo che un'applicazione A1 apra una connessione verso A2 per inviare ad A2 uno stream di oggetti • A1 associa alla connessione un ObjectOutputStream, mentre A2 associa alla medesima connessione un ObjectInputStream • Quando A1 crea l'ObjectOutputStream, viene registrato uno sullo stream un header che viene quindi inviato sulla connessione • Quando A2 crea l' ObjectInputStream – la JVM accede tenta di recuperare l'header dello stream dal socket associato alla connessione – se l'header non è presente, la JVM si blocca in attesa di ricevere l'header sul socket – ATTENZIONE: per prevenire situazioni di deadlock occorre porre attenzione sull'ordine con cui vengono creati gli stream di Input/Output Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 42 OBJECT INPUT/OUTPUT STREAM: DEADLOCK Se i due partners della connessione eseguono entrambi il seguente frammento di codice (s è il socket associato alla connessione) ObjectInputStream in = new ObjectInputStream(s.getInputStream( )); ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream( )); si verifica una situazione di deadlock.. Infatti, • entrambi tentano di leggere l'header dello stream dal socket • l'header viene generato quando viene viene creato l'ObjectOutputStream • nessuno dei due è in grado di generare l'ObjectOutputStream, perchè bloccato • E' sufficiente invertire l'ordine di creazione degli stream in uno dei partner Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 43 JAVA: LA SERIALIZZAZIONE • Il meccanismo di default offerto da JAVA è generale e le prestazioni non risultano quindi ottime i riferimenti agli oggetti sono memorizzati nella cache degli oggetti associata all'OutputStream il garbage collector non può recuperare memoria relativa agli oggetti scritti sullo stream • trade off tra convenienza e semplicità e performance Se la performance è un obiettivo primario della applicazione, allora occorre personalizzare il protocollo di serializzazione mediante l'implementazione della interfaccia Externalizable public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 44 INVIO OGGETTI SU STREAM Per inviare oggetti su connessioni TCP • associare i filtri ObjectInputStream/ObjectOutputStream stream di bytes associati al socket e restituiti getInputStream/getOutputStream • inviare/ricevere degli oggetti scritture/letture sullo stream sullo/dallo stream avviene agli da mediante – writeObject – ReadObject • i metodi precedenti implementano la serializzazione di un oggetto (discussa nella seconda parte della lezione) Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 45 INVIO DI OGGETTI import java.io.*; public class Studente implements Serializable { private int matricola; private String nome, cognome, corsoDiLaurea; public Studente(int matricola, String nome, String cognome, String corsoDiLaurea) {this.matricola = matricola; this.nome = nome; this.cognome = cognome; this.corsoDiLaurea = corsoDiLaurea;} public int getMatricola () { return matricola; } public String getNome () { return nome; } public String getCognome () { return cognome; } public String getCorsoDiLaurea () { return corsoDiLaurea; } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci } 46 INVIO DI OGGETTI SU STREMS import java.io.*; import java.net.*; public class Server { public static void main (String args[]) { try { ServerSocket server = new ServerSocket (3575); Socket clientsocket = server.accept(); ObjectOutputStream output = new ObjectOutputStream (clientsocket.getOutputStream ()); output.writeObject("<Welcome>"); Studente studente = new Studente (14520,"Mario","Rosso","Informatica"); output.writeObject(studente); output.writeObject("<Goodbye>"); clientsocket.close(); server.close();} catch (Exception e) { Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation } } } Laura Ricci 47 COME CHIUDERE UNO STREAM public class Client { public static void main (String args[ ]) { try {Socket socket = new Socket ("localhost",3575); ObjectInputStream input=newObjectInputStream(socket.getInputStream()); String beginMessage = (String) input.readObject(); System.out.println (beginMessage); Studente studente = (Studente) input.readObject(); System.out.print (studente.getMatricola()+" - "); System.out.print (studente.getNome()+""+studente.getCognome()+"- "); System.out.print (studente.getCorsoDiLaurea()+"\n"); String endMessage = (String)input.readObject(); System.out.println (endMessage); socket.close();} catch (Exception e) { System.out.println (e); } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation } } Laura Ricci 48 INVIO DI OGGETTI SU STREAMS Stampa prodotta lato Client <Welcome> 14520 - Mario Rossi - Informatica <Goodbye> Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 49 CHIUSURA DI STREAMS import java.net.*; import java.io.*; import java.util.*; public class closer { public static void main(String args[])throws Exception{ InetAddress ia = InetAddress.getByName("localhost"); Socket out =new Socket(ia,2500); OutputStream outs= out.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(outs); Date d= new Date(); oos.writeObject(d); out.shutdownOutput(); } } Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 50 CHIUSURA DI STREAMS import java.net.*; import java.io.*; import java.util.*; public class server { public static void main (String args[]) throws Exception {ServerSocket ss = new ServerSocket(2500); Socket s=ss.accept(); InputStream is = s.getInputStream(); ObjectInputStream ois = new ObjectInputStream(is); boolean go=true; while (go) {try{ Date d =(Date) ois.readObject(); System.out.println(d);} catch (IOException e) {System.out.println(e); go=false; }}}} Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 51 ASTA ELETTRONICA Sviluppare un programma client server per il supporto di un'asta elettronica. Ogni client possiede un budget massimo B da investire. Il client può richiedere al server il valore V della migliore offerta pervenuta fino ad un certo istante e decidere se abbandonare l'asta, oppure rilanciare. Se il valore ricevuto dal server supera B, l'utente abbandona l'asta, dopo aver avvertito il server. Altrimenti, il client rilancia, inviando al server un valore maggiore di V. Il server invia ai client che lo richiedono il valore della migliore offerta ricevuta fino ad un certo momento e riceve dai client le richieste di rilancio. Per ogni richiesta di rilancio, il server notifica al client se tale offerta può essere accettata (nessuno ha offerto di più nel frattempo), oppure è rifiutata. Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 52 ASTA ELETTRONICA Il server deve attivare un thread diverso per ogni client che intende partecipare all'asta. La comunicazione tra clients e server deve avvenire mediante socket TCP. Sviluppare due diverse versioni del programma che utilizzino, rispettivamente: la serializzazione offerta da JAVA in modo da scambiare oggetti tramite ule connessione TCP una codifica testuale dei messaggi spediti tra client e sever Dipartimento di Informatica Università degli studi di Pisa JAVA Serializzation Laura Ricci 53