Lezione n.6 LPR Informatica Applicata Serializzazione JAVA

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