Java - Programmazione di Reti

396
U Lezione 1: JAVA Tasks e Threads 1 Andrea Corradini Lezione n.1 LPR-B-09 JAVA: Tasks e Threads 22/9/2009 Andrea Corradini (basato su materiale di Laura Ricci e Marco Danelutto) Università degli Studi di Pisa Dipartimento di Informatica

Transcript of Java - Programmazione di Reti

Page 1: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 1Andrea Corradini

Lezione n.1LPR-B-09

JAVA: Tasks e Threads

22/9/2009Andrea Corradini

(basato su materiale di Laura Ricci e Marco Danelutto)

Università degli Studi di Pisa Dipartimento di Informatica

Page 2: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 2Andrea Corradini

PROGRAMMA DEL CORSO

Threads: Attivazione, Classe Thread,Interfaccia Runnable, Thread Pooling, Threads, Sincronizzazione su strutture dati condivise: metodi synchronized, wait, notify, notifyall

Thread Pooling: Meccanismi di gestione di pools di threads

Streams: Proprietà degli Streams, Tipi di streams, Composizione di streams, ByteArrayInputStream, ByteArrayOutputStream

Indirizzamento IP: Gestione degli Indirizzi IP in JAVA: La classe InetAddress

Meccanismi di Comunicazione in Rete: Sockets Connectionless e Connection Oriented

Connectionless Sockets: La classe Datagram Socket: creazione di sockets, generazione di pacchetti, timeouts, uso degli streams per la generazione di pacchetti di bytes, invio di oggetti su sockets connectionless.

Page 3: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 3Andrea Corradini

PROGRAMMA DEL CORSO

Multicast: La classe MulticastSocket, Indirizzi di Multicast, Associazione ad un gruppo di multicast. Proposte di reliable multicast (FIFO multicast,causal multicast, atomic multicast).

Connection Oriented Sockets: Le classi ServerSocket e Socket. Invio di oggetti su sockets TCP.

Il Paradigma Client/Server: Caratteristiche del paradigma client/ server, Meccanismi per l'individuazione di un servizio, architettura di un servizio di rete.

Oggetti Distribuiti: Remote Method Invocation, Definizione di Oggetti Remoti, Registrazione di Oggetti, Generazione di Stub e Skeletons.

Meccanismi RMI Avanzati: Il meccanismo delle callback.

Page 4: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 4Andrea Corradini

MULTITHREADING: DEFINIZIONI

Definizioni:

Thread: flusso sequenziale di esecuzione

Multithreading:

• consente di definire più flussi di esecuzione (threads) all’ interno dello stesso programma

• i threads possono essere eseguiti

• in parallelo (simultaneamente) se il programma viene eseguito su un multiprocessor

• in modo concorrente (interleaving) se il programma viene eseguito su un uniprocessor, ad esempio mediante time-sharing

Page 5: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 5Andrea Corradini

MULTITHREADING: MOTIVAZIONI

Migliorare le prestazioni di un programma:

• dividere il programma in diverse parti ed assegnare l'esecuzione di ogni parte ad un processore diverso

• su architetture di tipo uniprocessor: può migliorare l'uso della CPU quando il programma si blocca (es: I/O) implementazione di interfacce utente reattive

Web Server:

• Assegna un thread ad ogni richiesta

• Utilizza più CPU in modo da gestire in parallelo le richieste degli utenti

Interfacce reattive:

• gestione asincrona di eventi generati dall'interazione con l'utente

Page 6: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 6Andrea Corradini

MULTITHREADING: MOTIVAZIONI

Migliorare la progettazione del codice: Non solo una panacea per aumentare le prestazioni, ma uno strumento

per sviluppare software robusto e responsivo

Esempi: progettazione di un browser : mentre viene caricata una pagina, mostra

un'animazione. Inoltre mentre carico la pagina posso premere il bottone di stop ed interrompere il caricamento. Le diverse attività possono essere associati a threads diversi.

Progettazione di applicazioni complesse che richiedono la gestione contemporanea di più attività.

applicazioni interattive distribuite (giochi multiplayers): si devono gestire eventi provenienti dall'interazione con l'utente, dalla rete...

Page 7: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 7Andrea Corradini

TASKS E THREADS IN JAVA

• L'interfaccia java.lang.Runnable contiene un solo metodo

void run( )

• Un task è un oggetto (di una classe) che implementa l'intefaccia Runnable: la sua esecuzione inizia con l'invocazione di run()

• Un thread è un oggetto della classe java.lang.Thread, che implementa Runnable

• Attivare un thread significa iniziare un nuovo flusso di esecuzione per eseguire un determinato task

• Un thread viene attivato invocando il metodo

void start()

• La JVM (Java Virtual Machine) inizia l'esecuzione del thread invocandone il metodo run()

Page 8: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 8Andrea Corradini

THREAD IN UN PROGRAMMA JAVA

• IL thread main viene creato dalla JVM per avviare l'esecuzione di un'applicazione JAVA: il task eseguito è il metodo main(String [])della classe invocata, ad esempio MyClass se abbiamo eseguito da linea di comando

java MyClass

• Altri thread sono attivati automaticamente dalla JVM (sono thread daemons: gestore eventi interfaccia, garbage collector, ...)

• Ogni thread durante la sua esecuzione può attivare altri thread

• Un thread è un daemon se e solo se il thread che lo ha creato è un daemon

• Un programma JAVA termina quando sono terminati tutti i suoi thread che non sono daemons.

Page 9: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 9Andrea Corradini

ATTIVAZIONE DI THREADS

Per definire un task e eseguirlo in un nuovo thread si usano due tecniche: Si estende la classe Thread sovrascrivendo il metodo run(): questo è

possibile solo se non dobbiamo ereditare da un'altra classe. Per attivare il thread basta invocare start() su una istanza della classe.

oppure Si definisce una classe C che implementa Runnable. Quindi si crea una

nuova istanza di Thread, passando una istanza O di C come argomento, e si invoca start() sul thread.

Come funziona? Vediamo il metodo run() di Thread:

public Thread (Runnable target){

this.target = target}

public void run( ) {

if (target != null) { target.run( ); } }

Page 10: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 10Andrea Corradini

IL TASK DECOLLO

Esempio: Implementare un task Decollo che implementi un 'conto alla rovescia' e che, alla fine del conto, invii un segnale 'Via!'

public class Decollo implements Runnable {

int countDown = 10; // Predefinito

private static int taskCount = 0;

final int id= taskCount ++; // identifica il task

public Decollo( ) { }

public Decollo (int countDown) {this.countDown = countDown; }

public String status ( ) {return "#" + id + "(" +

(countDown > 0 ? countDown: "Via!!!")+"),"; }

Page 11: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 11Andrea Corradini

IL TASK DECOLLO

public void run( ) {

while (countDown-- > 0){System.out.print(status( ));try{ Thread.sleep(100);}

catch(InterruptedException e){ }}}}

public class MainThread {

public static void main(String[] args){decollo d= new Decollo(); d.run( ); System.out.println ("Aspetto il decollo");}}

OutputGenerato

#0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#0(Via!!!),Aspetto il decollo

Page 12: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 12Andrea Corradini

UN TASK NON E' UN THREAD!

• NOTA BENE: Nell'esempio precedente non viene creato alcun thread per

l'esecuzione del metodo run( )

• Il metodo run( ) viene eseguito all'interno del thread main, attivato per il

programma principale

• Invocando direttamente il metodo run( ) di un oggetto di tipo Runnable,

non si attiva alcun thread ma si esegue il task definito dal metodo run( )

nel thread associato al flusso di esecuzione del chiamante

• Per associare un nuovo thread di esecuzione ad un Task, occorre creare un

oggetto di tipo Thread e passargli il Task

Page 13: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 13Andrea Corradini

DECOLLO IN UN THREAD INDIPENDENTE

public class MainThread {public static void main(String [ ] args) { Decollo d = new Decollo();

Thread t = new Thread(d);t.start();System.out.println("Aspetto il Decollo"); }

}

Output generato (con alta probabilità, comunque può dipendere dallo

schedulatore):

Aspetto il decollo

#0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#0(Via!!!),

Page 14: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 14Andrea Corradini

DECOLLO IN PIU' THREAD

public class MoreThreads {

public static void main(String [ ]args) {for (int i=0; i<5; i++)

new Thread(new Decollo()).start();System.out.println("Aspetto il decollo");

}}

Possibile output generato:

#0(9),#1(9),Aspetto il decollo#2(9),#4(9),#3(9),#1(8),#0(8),#3(8),#4(8),#2(8),#1(7),#0(7),#2(7),#4(7),#3(7),#0(6),#4(6),#2(6),#3(6),#1(6),#2(5),#1(5),#3(5),#4(5),#0(5),#2(4),#3(4),#0(4),#4(4),#1(4),#2(3),#0(3),#3(3),#4(3),#1(3),#3(2),#0(2),#2(2),#4(2),#1(2),#3(1),#2(1),#0(1),#1(1),#4(1),#3(Via!!!),#4(Via!!!),#2(Via!!!),#0(Via!!!),#1(Via!!!),

Page 15: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 15Andrea Corradini

LA CLASSE java.lang.Thread

La classe java.lang.Thread contiene membri per:

• costruire un thread interagendo con il sistema operativo ospite

• attivare, sospendere, interrompere i thread

• non contiene i metodi per la sincronizzazione tra i thread, che sono definiti in java.lang.Object.

Costruttori:

• Vari: differiscono per parametri utilizzati (esempio: task da eseguire, nome del thread, gruppo cui appartiene il thread: vedere API)

Metodi

• Possono essere utilizzati per interrompere, sospendere un thread, attendere la terminazione di un thread + un insieme di metodi set e get per impostare e reperire le caratteristiche di un thread esempio: assegnare nomi e priorità ai thread

Page 16: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 16Andrea Corradini

LA CLASSE java.lang.Thread: start()

Il metodo start( )

• segnala allo schedulatore della JVM che il thread può essere attivato

(invoca un metodo nativo). L'ambiente del thread viene inizializzato

• ritorna immediatamente il controllo al chiamante, senza attendere che il

thread attivato inizi la sua esecuzione.

NOTA: la stampa del messaggio “Aspetto il decollo” è nel mezzo di

quelle effettuate dai threads. Questo significa che il controllo è stato

restituito al thread chiamante (il thread associato al main) prima che

sia terminata l'esecuzione dei threads attivati

Page 17: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 17Andrea Corradini

LA CLASSE java.lang.Thread: run()

• La classe Thread implementa l'interfaccia Runnable e quindi contiene l'implementazione del metodo run( )

public void run( ) {if (target != null) { target.run( ); } }

target = riferimento all'oggetto Runnable passato al momento della creazione

oppure null.

• L'attivazione di un thread mediante la start() causa l'invocazione del metodo run( ) precedente. A sua volta, viene invocato il metodo run( ) sull'oggetto che implementa Runnable (se questo è presente).

• Qualsiasi istruzione eseguita dal thread fa parte di run( ) o di un metodo invocato da run( ). Inoltre il thread termina con l'ultima istruzione di run( ).

• Dopo la terminazione un thread non può essere riattivato

Page 18: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 18Andrea Corradini

ESTENSIONE DELLA CLASSE THREADS

Creazione ed attivazione di threads: un approccio alternativo

• creare una classe C che estenda la classe Thread

• effettuare un overriding del metodo run( ) definito all'interno della

classe Thread

• Istanziare un oggetto O di tipo C. O è un thread il cui comportamento

è programmato nel metodo run( ) riscritto in C

• Invocare il metodo start( ) su O. Tale metodo attiva il thread ed

invoca il metodo riscritto.

Page 19: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 19Andrea Corradini

DECOLLO COME SOTTOCLASSE DI THREAD

public class DecolloThread extends Thread {.......

public void run( ) {

while (countDown-- > 0){

System.out.print(status( ));

try{ Thread.sleep(100);

} catch(InterruptedException e){ } }}}

public class MainDecolloThread {

public static void main(String [ ]args) {

DecolloThread d = new DecolloThread( );

d.start();

System.out.println("Aspetto il Decollo"); }}

Page 20: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 20Andrea Corradini

GERARCHIA DELLE CLASSI

• Thread estende Object e implementa l'interfaccia Runnable

• DecolloThread estende Thread e sovrascrive il metodo run() di Thread

Object

Thread

DecolloThread

Runnable

implements

Page 21: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 21Andrea Corradini

QUANDO E' NECESSARIO USARE LA RUNNABLE

In JAVA una classe può estendere una solo altra classe (eredità singola)

⇒La classe i cui oggetti devono essere eseguiti come thread non può

estendere altre classi.

Questo può risultare svantaggioso in diverse situazioni.

Esempio: Gestione degli eventi (es: movimento mouse, tastiera…) la classe che gestisce l’evento deve estendere una classe predefinita

JAVA inoltre può essere necessario eseguire il gestore come un thread

separato

Page 22: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 22Andrea Corradini

GESTIONE DEI THREADS

• public static native Thread currentThread ( ) In un ambiente multithreaded, lo stesso metodo può essere

eseguito in modo concorrente da più di un thread. Questo metodo restituisce un riferimento al thread che sta eseguendo un segmento di codice

• public final void setName(String newName) • public final String getName( )

consentono, rispettivamente, di associare un nome ad un thread e di reperire il nome assegnato

• public static native void sleep (long mills) sospende l'esecuzione del thread che invoca il metodo per mills

millisecondi. Durante questo intervallo di tempo il thread non utilizza la CPU. Non è possibile porre un altro thread in sleep.

Page 23: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 23Andrea Corradini

ESERCIZIO 1

• Scrivere un programma JAVA che attivi K thread, chiamati “T1”, “T2”, ..., “TK”. Tutti i thread sono caratterizzati dallo stesso comportamento: ogni thread stampa i primi N numeri naturali, senza andare a capo (K e N sono dati in input dall'utente). Accanto ad ogni numero deve essere visualizzato il nome del thread che lo ha generato, ad esempio usando il formato “: n [Tk] :”. Tra la stampa di un numero e quella del numero successivo ogni thread deve sospendersi per un intervallo di tempo la cui durata è scelta in modo casuale tra 0 e 1000 millisecondi.

• Sviluppare due diverse versioni del programma che utilizzino le due tecniche per l'attivazione di threads presentate in questa lezione.

Page 24: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 24Andrea Corradini

COME INTERROMPERE UN THREAD

• Un thread può essere interrotto, durante il suo ciclo di vita, ad esempio mentre sta 'dormendo' in seguito all'esecuzione di una sleep()

• L'interruzione di un thread causa una InterruptedException

public class SleepInterrupt implements Runnable {public void run ( ){ try{ System.out.println("vado a dormire per 20 secondi");

Thread.sleep(20000);

System.out.println ("svegliato"); }catch ( InterruptedException x )

{ System.out.println ("interrotto"); return;};System.out.println("esco normalmente");}}

Page 25: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 25Andrea Corradini

COME INTERROMPERE UN THREAD

public class SleepMain {

public static void main (String args [ ]) {SleepInterrupt si = new SleepInterrupt();Thread t = new Thread (si);t.start ( );try {

Thread.sleep(2000);} catch (InterruptedException x) { };System.out.println("Interrompo l'altro thread");t.interrupt( );

System.out.println ("sto terminando...");

} }

Page 26: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 26Andrea Corradini

COME INTERROMPERE UN THREAD

• Il metodo interrupt( ): interrompe il thread causando una InterruptedException se era sospeso

(con wait(), sleep(), join(), I/O) altrimenti imposta a true un flag nel descrittore del thread

E' possibile testare il valore del flag mediante: public static boolean interrupted ( ) STATIC !!!

restituisce il valore del flag (relativo al thread in esecuzione); riporta il valore del flag a false

public boolean isInterrupted ( )restituisce il valore del flag, relativo al thread su cui è invocato

Nota: se esiste un interrupt pendente al momento dell'esecuzione della

sleep( ), viene sollevata immediatamenete una InterruptedException.

Page 27: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 27Andrea Corradini

ESERCIZIO 2: INTERROMPERE UN THREAD

Scrivere un programma che avvia un thread che va in sleep per 10 secondi. Il programma principale interrompe il thread dopo 5 secodni. Il thread deve catturare l'eccezione e stampare il tempo trascorso in sleep.

Per ottenere l'ora corrente usare il metodo System.currentTimeMillis(), consultandone la documentazione on line.

Page 28: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 28Andrea Corradini

Esercizio 3: CALCOLO DI π

Scrivere un programma che attiva un thread T che effettua il calcolo approssimato di π. Il programma principale riceve in input da linea di comando due argomenti:

un parametro che indica il grado di accuratezza (accuracy) per il calcolo di π

il tempo massimo di attesa dopo cui il programma principale interrompe il thread T.

Il thread T effettua un ciclo infinito per il calcolo di π usando la serie di Gregory-Leibniz ( π = 4/1 – 4/3 + 4/5 - 4/7 + 4/9 - 4/11 ...). Il thread esce dal ciclo quando una delle due condizioni seguenti risulta verificata:

1) il thread è stato interrotto, oppure

2) la differenza tra il valore stimato di π ed il valore Math.PI (della

libreria Java) è minore di accuracy

Page 29: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 29Andrea Corradini

PRIORITA' DEI THREADS

• Ogni thread ha una priorità che può essere cambiata durante l'esecuzione. La priorità rappresenta un suggerimento allo schedulatore sull'ordine con cui i threads possono essere inviati in esecuzione

• La priorità viene ereditata dal thread padre

• Metodi per gestire la priorità public final void setPriority (int newPriority)

Può essere invocato prima dell'attivazione del thread o durante la sua esecuzione (da un thread che ne ha il diritto)

public final int getPriority ( ) Thread.MAX_PRIORITY (= 10) Thread.MIN_PRIORITY (= 1) Thread.NORM_PRIORITY (= 5)

Page 30: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 30Andrea Corradini

THREAD CON DIVERSE PRIORITA'

Scriviamo un programma dove il thread main ha priorità 5 (come da default), e attiva i thread

Thread A con priorità 8 e poi 3 Thread B con priorità 2 Thread D con priorità 7, che crea

Thread C con la stessa priorità, 7.

Page 31: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 31Andrea Corradini

THREAD PRIORITY: Definizione dei task

public class Task1 implements Runnable{

public void run( ) {for (int i = 0; i < 4; i++){

Thread t = Thread.currentThread ( );System.out.println(t.getName() +

" ha priorita' " + t.getPriority());try {Thread.sleep (2000);} catch(InterruptedException x) {}} } }

public class Task2 implements Runnable{

public void run( ) {Thread tC = new Thread(new Task1(), "thread C");tC.start(); new Task1().run(); } }

Page 32: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 32Andrea Corradini

THREAD PRIORITY: il main

public class MainPriority{

public static void main (String[ ] args) {Thread tA = new Thread(new Task1(),"thread A");Thread tB = new Thread(new Task1(),"thread B");Thread tD = new Thread(new Task2(),"thread D");tA.setPriority(8); tB.setPriority(2); tD.setPriority(7);tA.start(); tB.start(); tD.start();try{Thread.sleep(3000);}catch(InterruptedException x) { }tA.setPriority(3);System.out.println("main ha priorita' " +

Thread.currentThread().getPriority()); } }

Page 33: Java - Programmazione di Reti

ULezione 1: JAVA Tasks e Threads 33Andrea Corradini

THREAD PRIORITY: Un possibile output

thread B ha priorita' 2thread D ha priorita' 7thread C ha priorita' 7thread A ha priorita' 8thread B ha priorita' 2thread D ha priorita' 7thread A ha priorita' 8thread C ha priorita' 7main ha priorita' 5thread B ha priorita' 2thread D ha priorita' 7thread A ha priorita' 3thread C ha priorita' 7thread B ha priorita' 2thread D ha priorita' 7thread A ha priorita' 3thread C ha priorita' 7

Page 34: Java - Programmazione di Reti

ULezione 2: JAVA pooling 1Andrea Corradini

Lezione n.2LPR-B-09

Thread Pooling e Callable

29/9-6/10/2009Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 35: Java - Programmazione di Reti

ULezione 2: JAVA pooling 2Andrea Corradini

ATTENDERE LA TERMINAZIONE DI UN THREAD: METODO join()

Un thread J può invocare il motodo join( ) su un oggetto T di tipo thread

J rimane sospeso sulla join( ) fino alla terminazione di T.

Quando T termina, J riprende l'esecuzione con l'istruzione successiva alla

join( ).

Un thread sospeso su una join( ) può essere interrotto da un altro thread

che invoca su di esso il metodo interrupt( ).

Il metodo può essere utilizzato nel main per attendere la terminazione di

tutti i threads attivati.

Page 36: Java - Programmazione di Reti

ULezione 2: JAVA pooling 3Andrea Corradini

JOINING A THREAD

public class Sleeper extends Thread {

private int period;

public Sleeper (String name, int sleepPeriod){super(name);period = sleepPeriod;start( ); }

public void run( ){try{

sleep (period); }

catch (InterruptedException e){System.out.println(getName( )+" e' stato interrotto"); return;}

System.out.println(getName()+" e' stato svegliato normalmente");}}

Page 37: Java - Programmazione di Reti

ULezione 2: JAVA pooling 4Andrea Corradini

JOINING A THREAD

public class Joiner extends Thread {

private Sleeper sleeper;

public Joiner(String name, Sleeper sleeper){super(name);this.sleeper = sleeper;start( ); }

public void run( ){try{

sleeper.join( );}catch(InterruptedException e) {

System.out.println("Interrotto"); return; }

System.out.println(getName( )+" join completed"); }}

Page 38: Java - Programmazione di Reti

ULezione 2: JAVA pooling 5Andrea Corradini

JOINING A THREAD

public class Joining {

public static void main(String[ ] args){Sleeper assonnato = new Sleeper("Assonnato", 1500);Sleeper stanco = new Sleeper("Stanco", 1500);

new Joiner("WaitforAssonnato", assonnato);new Joiner("WaitforStanco", stanco);stanco.interrupt(); } }

Output:

Stanco è stato interrotto

WaitforStanco join completed

Assonnato è stato svegliato normalmente

WaitforAssonnato join completed

Page 39: Java - Programmazione di Reti

ULezione 2: JAVA pooling 6Andrea Corradini

THREAD POOLING: CONCETTI FONDAMENTALI

• L'utente struttura l'applicazione mediante un insieme di tasks.

• Task = segmento di codice che può essere eseguito da un “esecutore”. Può

essere definito come un oggetto di tipo Runnable

• Thread = esecutore in grado di eseguire tasks.

• Uno stesso thread può essere utilizzato per eseguire diversi tasks, durante la

sua vita.

• Thread Pool = Struttura dati (normalmente con dimensione massima

prefissata), che contiene riferimenti ad un insieme di threads

• I thread del pool vengono utilizzati per eseguire i tasks sottomessi

dall'utente.

Page 40: Java - Programmazione di Reti

ULezione 2: JAVA pooling 7Andrea Corradini

THREAD POOLING: MOTIVAZIONI

• Tempo stimato per la creazione di un thread: qualche centinaio di microsecondi.

• La creazione di un alto numero di threads può non essere tollerabile per certe applicazioni.

• Thread Pooling– Diminuisce l'overhead dovuto alla creazione di un gran numero di

thread: lo stesso thread può essere riutilizzato per l'esecuzione di più di un tasks

– Permette una semplificazione e una migliore strutturazione del codice dell'applicazione: tutta la gestione dei threads può essere delegata al gestore del pool (che va può essere riutilizzato in altre applicazioni...)

Page 41: Java - Programmazione di Reti

ULezione 2: JAVA pooling 8Andrea Corradini

THREAD POOLING: USO

L'utente

• Definisce i tasks dell'applicazione

• Crea un pool di thread e stabilisce una politica per la gestione dei threads all'interno del pool. La politica stabilisce:

– quando i threads del pool vengono attivati: (al momento della creazione del pool, on demand, in corrispondenza dell'arrivo di un nuovo task,....)

– se e quando è opportuno terminare l'esecuzione di un thread (ad esempio se non c'è un numero sufficiente di tasks da eseguire)

• Sottomette i tasks per l'esecuzione al pool di thread.

Page 42: Java - Programmazione di Reti

ULezione 2: JAVA pooling 9Andrea Corradini

THREAD POOLING: IL GESTORE

• L'applicazione sottomette un task T al gestore del pool di thread

• Il gestore sceglie un thread dal pool per l'esecuzione di T.

Le scelte possibili sono:– utilizzare un thread attivato in precedenza, ma inattivo al momento

dell'arrivo del nuovo task– creare un nuovo thread, purchè non venga superata la dimensione

massima del pool– memorizzare il task in una struttura dati, in attesa di eseguirlo– respingere la richiesta di esecuzione del task

• Il numero di threads attivi nel pool può variare dinamicamente

Page 43: Java - Programmazione di Reti

ULezione 2: JAVA pooling 10Andrea Corradini

LIBRERIA java.util.concurrent

• L'implementazione del thread pooling:

– Fino a J2SE 1.4 doveva essere realizzata a livello applicazione

– J2SE 5.0 introduce la libreria java.util.concurrent che contiene

metodi per

• Creare un pool di thread e il gestore associato

• Definire la struttura dati utilizzata per la memorizzazione dei

tasks in attesa

• Decidere specifiche politiche per la gestione del pool

Page 44: Java - Programmazione di Reti

ULezione 2: JAVA pooling 11Andrea Corradini

CREARE UN THREADPOOL EXECUTOR

Il package java.util.concurrent definisce:

• Alcune interfacce che definiscono servizi generici di esecuzione...public interface Executor {

public void execute (Runnable task); }

public interface ExecutorService extends Executor{... }● diverse classi che implementano ExecutorService (ThreadPoolExecutor,

ScheduledThreadPoolExecutor, ...) ● la classe Executors che opera come una Factory in grado di generare

oggetti di tipo ExecutorService con comportamenti predefiniti.

I tasks devono essere incapsulati in oggetti di tipo Runnable e passati a

questi esecutori, mediante invocazione del metodo execute( )

Page 45: Java - Programmazione di Reti

ULezione 2: JAVA pooling 12Andrea Corradini

ESEMPI: IL TASK

public class TakeOff implements Runnable{

int countDown = 3; // Predefinito

public String status( ){return "#" + Thread.currentThread() +

"(" + (countDown > 0 ? countDown: "Via!!!") + "),";

}

public void run( ) {while (countDown-- > 0){

System.out.println(status());try{ Thread.sleep(100);} catch(InterruptedException e){ }

}

}}

Page 46: Java - Programmazione di Reti

ULezione 2: JAVA pooling 13Andrea Corradini

import java.util.concurrent.*;

public class Esecutori1 {

public static void main(String[ ] args) {ExecutorService exec = Executors.newCachedThreadPool();for (int i=0; i<3; i++) {

exec.execute(new TakeOff( )); } } }

newCachedThreadPool ( ) crea un pool in cui quando viene sottomesso un task

• viene creato un nuovo thread se tutti i thread del pool sono occupati nell'esecuzione di altri tasks.

• viene riutilizzato un thread che ha terminato l'esecuzione di un task precedente, se disponibile

Se un thread rimane inutilizzato per 60 secondi, la sua esecuzione termina e

viene rimosso dalla cache.

THREAD POOLING: ESEMPIO 1

Page 47: Java - Programmazione di Reti

ULezione 2: JAVA pooling 14Andrea Corradini

ESEMPIO1: OUTPUT

Output del programma:

#Thread[pool-1-thread-2,5,main](2)

#Thread[pool-1-thread-1,5,main](2)

#Thread[pool-1-thread-3,5,main](2)

#Thread[pool-1-thread-3,5,main](1),

#Thread[pool-1-thread-2,5,main](1),

#Thread[pool-1-thread-1,5,main](1)

#Thread[pool-1-thread-2,5,main](Via!!!),

#Thread[pool-1-thread-1,5,main](Via!!!)

#Thread[pool-1-thread-3,5,main](Via!!!),

Page 48: Java - Programmazione di Reti

ULezione 2: JAVA pooling 15Andrea Corradini

THREAD POOLING: ESEMPIO 2

import java.util.concurrent.*;

public class Esecutori2 {

public static void main(String[]args){ExecutorService exec = Executors.newCachedThreadPool();for (int i=0; i<3; i++){

exec.execute(new TakeOff( ));try {Thread.sleep (4000);}

catch(InterruptedException e) { } } } }

La sottomissione di tasks al pool viene distanziata di 4 secondi. In questo modo

l'esecuzione precedente è terminata ed è possibile riutilizzare un thread

attivato precedentemente

Page 49: Java - Programmazione di Reti

ULezione 2: JAVA pooling 16Andrea Corradini

ESEMPIO 2: OUTPUT

#Thread[pool-1-thread-1,5,main](2)

#Thread[pool-1-thread-1,5,main](1),

#Thread[pool-1-thread-1,5,main](Via!!!),

#Thread[pool-1-thread-1,5,main](2)

#Thread[pool-1-thread-1,5,main](1)

#Thread[pool-1-thread-1,5,main](Via!!!)

#Thread[pool-1-thread-1,5,main](2)

#Thread[pool-1-thread-1,5,main](1)

#Thread[pool-1-thread-1,5,main](Via!!!),

Page 50: Java - Programmazione di Reti

ULezione 2: JAVA pooling 17Andrea Corradini

THREAD POOLING: ESEMPIO 3

import java.util.concurrent.*;

public class Esecutori3 {

public static void main(String[]args){

ExecutorService exec = Executors.newFixedThreadPool(2);

for (int i=0; i<3; i++){

exec.execute(new TakeOff());} } }

newFixedThreadPool (int i) crea un pool in cui, quando viene sottomesso un task

• Viene riutilizzato un thread del pool, se inattivo

• Se tutti i thread sono occupati nell'esecuzione di altri tasks, il task viene inserito in una coda, gestita dall'ExecutorService e condivisa da tutti i thread.

Page 51: Java - Programmazione di Reti

ULezione 2: JAVA pooling 18Andrea Corradini

ESEMPIO 3: OUTPUT

#Thread[pool-1-thread-1,5,main](2),

#Thread[pool-1-thread-2,5,main](2),

#Thread[pool-1-thread-2,5,main](1),

#Thread[pool-1-thread-1,5,main](1),

#Thread[pool-1-thread-1,5,main](Via!!!),

#Thread[pool-1-thread-2,5,main](Via!!!),

#Thread[pool-1-thread-1,5,main](2),

#Thread[pool-1-thread-1,5,main](1),

#Thread[pool-1-thread-1,5,main](Via!!!),

Page 52: Java - Programmazione di Reti

ULezione 2: JAVA pooling 19Andrea Corradini

THREAD POOL EXECUTOR

package java.util.concurrent;

public class ThreadPoolExecutor implements ExecutorService{

public ThreadPoolExecutor ( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue <Runnable> workqueue);

... }

• crea un oggetto di tipo ExecutorService

• consente di definire gestori di thread pool con una politica di gestione personalizzata

Page 53: Java - Programmazione di Reti

ULezione 2: JAVA pooling 20Andrea Corradini

THREAD POOL EXECUTOR

public ThreadPoolExecutor ( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue <Runnable> workqueue);

... }

• corePoolSize, maximumPoolSize, e keepAliveTime controllano la

gestione dei threads del pool

• workqueue è una struttura dati usata per memorizzare gli eventuali

tasks in attesa di esecuzione

Page 54: Java - Programmazione di Reti

ULezione 2: JAVA pooling 21Andrea Corradini

THREAD POOL: GESTIONE DINAMICA

• corePoolSize: dimensione minima del pool

– È possibile allocare corePoolSize thread al momento della creazione

del pool mediante il metodo prestartAllCoreThreads( ). I thread

creati rimangono inattivi in attesa di tasks da eseguire.

– Oppure i thread possono essere creati “on demand”. Quando viene

sottomesso un nuovo task, viene creato un nuovo thread, anche se

alcuni dei threads già creati sono inattivi. L'obiettivo è di riempire il

“core” del pool prima possibile.

• maximumPoolSize:dimensione massima del pool

Page 55: Java - Programmazione di Reti

ULezione 2: JAVA pooling 22Andrea Corradini

THREAD POOL: GESTIONE DINAMICA

• Se sono in esecuzione tutti i core thread, un nuovo task sottomesso viene inserito in una coda Q.– Q deve essere una istanza di BlockingQueue<Runnable>– Q viene passata al momento della costruzione del threadPoolExecutor

(ultimo parametro del costruttore)– E' possibile scegliere diversi tipi di coda (sottoclassi di

BlockingQueue). Il tipo di coda scelto influisce sullo scheduling.

• I task vengono poi prelevati da Q e inviati ai threads che si rendono disponibili

• Solo quando Q risulta piena si crea un nuovo thread attivando così kthreads, corePoolSize ≤ k ≤ maxPoolSize

Page 56: Java - Programmazione di Reti

ULezione 2: JAVA pooling 23Andrea Corradini

THREAD POOL: GESTIONE DINAMICA

Da questo punto in poi, quando viene sottomesso un nuovo task T

• se esiste un thread th inattivo, T viene assegnato a th

• se non esistono threads inattivi, si preferisce sempre accodare un

task piuttosto che creare un nuovo thread

• solo se la coda è piena, si attivano nuovi threads

• Se la coda è piena e sono attivi MaxPoolSize threads, il task viene

respinto e viene sollevata un'eccezione

Page 57: Java - Programmazione di Reti

ULezione 2: JAVA pooling 24Andrea Corradini

THREAD POOL: GESTIONE DINAMICA

Supponiamo che un thread th termini l'esecuzione di un task, e che il pool

contenga k threads

• Se k <= core: il thread si mette in attesa di nuovi tasks da eseguire. L'attesa ė indefinita.

• Se k > core, si considera il timeout definito al momento della costruzione del thread pool– se nessun task viene sottomesso entro il timeout, th termina la sua

esecuzione, riducendo così il numero di threads del pool

• Il timeout è determinato dai parametri long keepAliveTime e TimeUnit unit del costruttore, quindi consiste di: – un valore (es: 50000L) e – l'unità di misura utilizzata (es: TimeUnit.MILLISECONDS)

Page 58: Java - Programmazione di Reti

ULezione 2: JAVA pooling 25Andrea Corradini

THREAD POOL: TIPI DI CODA

• SynchronousQueue: dimensione uguale a 0. Ogni nuovo task T

– viene eseguito immediatamente oppure respinto.

– T viene eseguito immediatamente se esiste un thread inattivo oppure

se è possibile creare un nuovo thread (numero di threads ≤

maxPoolSize)

• LinkedBlockingQueue: dimensione illimitata

– E' sempre possibile accodare un nuovo task, nel caso in cui tutti i tasks

attivi nell'esecuzione di altri tasks

– La dimensione del pool di non supererà mai core

• ArrayBlockingQueue: dimensione limitata, stabilita dal programmatore

Page 59: Java - Programmazione di Reti

ULezione 2: JAVA pooling 26Andrea Corradini

THREAD POOLING: UN ESEMPIO

• Dato un intero K, si vuole calcolare, per ogni valore n < K il valore dell'n-

esimo numero di Fibonacci

• Si definisce un task T che effettua il calcolo del numero di Fibonacci di n

(valore passato come parametro)

• Si attiva un ThreadPoolExecutor, definendo la politica di gestione del pool

di thread mediante i parametri passati al costruttore

• Si passa all'esecutore una istanza di T per ogni n < K, invocando il metodo

execute()

Page 60: Java - Programmazione di Reti

ULezione 2: JAVA pooling 27Andrea Corradini

FIBONACCI TASK (I)

public class FibTask implements Runnable{int n; String id;public FibTask(int n, String id){

this.n = n; this.id = id;} private int fib(int n){

if (n == 0 || n == 1) return n;if (n==1) return 1;return fib(n - 1) + fib(n - 2);

}

Page 61: Java - Programmazione di Reti

ULezione 2: JAVA pooling 28Andrea Corradini

FIBONACCI TASK (II)

public void run( ){try{

Thread t = Thread.currentThread ( );System.out.println("Starting task " + id + " su " + n + " eseguito dal thread " + t.getName( ));System.out.println("Risultato " + fib(n) + " da task " + id +

" eseguito dal thread " + t.getName( ));} catch (Exception e){

e.printStackTrace();}

}

}

Page 62: Java - Programmazione di Reti

ULezione 2: JAVA pooling 29Andrea Corradini

FIBONACCI THREAD POOL

import java.util.concurrent.*;

public class ThreadPoolTest {

public static void main (String [] args){

int nTasks = Integer.parseInt(args[0]); // # di tasks da eseguire// dimensione del core pool

int corePoolSize = Integer.parseInt(args[1]);

// massima dimensione del pool

int maxPoolSize = Integer.parseInt(args[2]);

ThreadPoolExecutor tpe = new ThreadPoolExecutor (corePoolSize,maxPoolSize,50000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>( ) );

Page 63: Java - Programmazione di Reti

ULezione 2: JAVA pooling 30Andrea Corradini

FIBONACCI THREAD POOL

FibTask [ ] tasks = new FibTask[nTasks];

for (int i=0; i< nTasks; i++){

tasks[i] = new FibTask(i, "Task" + i);

tpe.execute(tasks[i]);

System.out.println("dimensione del pool " + tpe.getPoolSize());

}

tpe.shutdown();

}

}

Page 64: Java - Programmazione di Reti

ULezione 2: JAVA pooling 31Andrea Corradini

GESTIONE DINAMICA: ESEMPI

Parametri: tasks= 8, core = 3, MaxPoolSize= 4, SynchronousQueue, timeout=50000msecdimensione del pool 1Starting task Task0 eseguito da pool-1-thread-1Risultato 0 da task Task0 eseguito dapool-1-thread-1dimensione del pool 2dimensione del pool 3dimensione del pool 3Starting task Task3 eseguito da pool-1-thread-1Starting task Task1 eseguito da pool-1-thread-2Starting task Task2 eseguito da pool-1-thread-3dimensione del pool 4Risultato 1 da task Task1 eseguito dapool-1-thread-2Starting task Task4 eseguito da pool-1-thread-4RisultatO 2 da task Task3 eseguito dapool-1-thread-1Risultato 1 da task Task2 eseguito dapool-1-thread-3java.util.concurrent.RejectedExecutionExceptionRisultato 3 da task Task4 eseguito dapool-1-thread-4

Page 65: Java - Programmazione di Reti

ULezione 2: JAVA pooling 32Andrea Corradini

GESTIONE DINAMICA: ESEMPI

Tutti I threads attivati inizialmente mediante tpe.prestartAllCoreThreads( );Parametri: tasks= 8, core = 3, MaxPoolSize= 4, SynchronousQueuedimensione del pool 3Starting task Task0 eseguito da pool-1-thread-3dimensione del pool3Risultato 0 da task Task0 eseguito da pool-1-thread-3dimensione del pool 3Starting task Task2 eseguito da pool-1-thread-1Starting task Task1 eseguito da pool-1-thread-2Risultato 1 da task Task2 eseguito dapool-1-thread-1Risultato 1 da task Task1 eseguito dapool-1-thread-2Starting task Task3 eseguito da pool-1-thread-3dimensione del pool 3Risultato 2 da task Task3 eseguito dapool-1-thread-3dimensione del pool 3

Page 66: Java - Programmazione di Reti

ULezione 2: JAVA pooling 33Andrea Corradini

GESTIONE DINAMICA: ESEMPI

(CONTINUA)

Starting task Task4 eseguito da pool-1-thread-2dimensione del pool 3Starting task Task5 eseguito da pool-1-thread-3Risultato 3 da task Task4 eseguito dapool-1-thread-2dimensione del pool 3Starting task Task6 eseguito da pool-1-thread-1Risultato 5 da task Task5 eseguito dapool-1-thread-3dimensione del pool 3Starting task Task7 eseguito da pool-1-thread-2Risultato 8 da task Task6 eseguito dapool-1-thread-1Risultato 13 da task Task7 eseguito dapool-1-thread-2

Page 67: Java - Programmazione di Reti

ULezione 2: JAVA pooling 34Andrea Corradini

GESTIONE DINAMICA: ESEMPI

Parametri: tasks= 10, core = 3, MaxPoolSize= 4, SynchronousQueue,timeout=0msecdimensione del pool 1Starting task Task0 eseguito da pool-1-thread-1Risultato 0 da task Task0 eseguito dapool-1-thread-1dimensione del pool 2Starting task Task1 eseguito da pool-1-thread-2Risultato 1 da task Task1 eseguito dapool-1-thread-2dimensione del pool 3dimensione del pool 3Starting task Task2 eseguito da pool-1-thread-3Starting task Task3 eseguito da pool-1-thread-2dimensione del pool 3Starting task Task4 eseguito da pool-1-thread-1Risultato 1 da task Task2 eseguito dapool-1-thread-3Risultato 2 da task Task3 eseguito dapool-1-thread-2dimensione del pool 4

Page 68: Java - Programmazione di Reti

ULezione 2: JAVA pooling 35Andrea Corradini

GESTIONE DINAMICA:ESEMPI

(CONTINUA)

Risultato 3 da task Task4 eseguito dapool-1-thread-1Starting task Task5 eseguito da pool-1-thread-4dimensione del pool 3Starting task Task6 eseguito da pool-1-thread-2Risultato 5 da task Task5 eseguito dapool-1-thread-4Starting task Task7 eseguito da pool-1-thread-1dimensione del pool 3Risultato 8 da task Task6 eseguito dapool-1-thread-2dimensione del pool 3Starting task Task8 eseguito da pool-1-thread-4dimensione del pool 3Starting task Task9 eseguito da pool-1-thread-2Risultato 13 da task Task7 eseguito dapool-1-thread-1Risultato 21 da task Task8 eseguito dapool-1-thread-4Risultato 34 da task Task9 eseguito dapool-1-thread-2

Page 69: Java - Programmazione di Reti

ULezione 2: JAVA pooling 36Andrea Corradini

GESTIONE DINAMICA: ESEMPI

Parametri: tasks= 10, core = 3, MaxPoolSize= 4,LinkedBlockingQueuedimensione del pool 1Starting task Task0 eseguito da pool-1-thread-1Risultato 0 da task Task0 eseguito dapool-1-thread-1dimensione del pool 2dimensione del pool 3Starting task Task1 eseguito da pool-1-thread-2Risultato 1 da task Task1 eseguito dapool-1-thread-2Starting task Task3 eseguito da pool-1-thread-2dimensione del pool 3Risultato 2 da task Task3 eseguito dapool-1-thread-2dimensione del pool 3Starting task Task2 eseguito da pool-1-thread-3Starting task Task4 eseguito da pool-1-thread-1Starting task Task5 eseguito da pool-1-thread-2dimensione del pool 3

Page 70: Java - Programmazione di Reti

ULezione 2: JAVA pooling 37Andrea Corradini

GESTIONE DINAMICA:ESEMPI

(CONTINUA)

Risultato 1 da task Task2 eseguito dapool-1-thread-3Risultato 3 da task Task4 eseguito dapool-1-thread-1Risultato 5 da task Task5 eseguito dapool-1-thread-2dimensione del pool 3Starting task Task6 eseguito da pool-1-thread-3dimensione del pool 3Starting task Task7 eseguito da pool-1-thread-1Risultato 8 da task Task6 eseguito dapool-1-thread-3dimensione del pool 3Starting task Task8 eseguito da pool-1-thread-2Risultato 13 da task Task7 eseguito dapool-1-thread-1dimensione del pool 3Starting task Task9 eseguito da pool-1-thread-3Risultato 21 da task Task8 eseguito dapool-1-thread-2Risultato 34 da task Task9 eseguito dapool-1-thread-3

Page 71: Java - Programmazione di Reti

ULezione 2: JAVA pooling 38Andrea Corradini

TERMINAZIONE DI THREADS

• La JVM termina la sua esecuzione quando tutti i thread (non demoni) terminano la loro esecuzione

• Poiché un ExecutorService esegue i tasks in modo asincrono rispetto alla loro sottomissione, è necessario ridefinire il concetto di terminazione, nel caso si utilizzi un ExecutorService

• Un ExecutorService mette a disposizione del programmatore diversi metodi per effettuare lo 'shutdown' dei thrad del pool

• La terminazione può avvenire

in modo graduale. Si termina l'esecuzione dei tasks già sottomessi, ma non si inizia l'esecuzione di nuovi tasks

in modo istantaneo. Terminazione immediata

Page 72: Java - Programmazione di Reti

ULezione 2: JAVA pooling 39Andrea Corradini

TERMINAZIONE DI EXECUTORS

Alcuni metodi definiti dalla interfaccia ExecutorService

• void shutdown( )

• List<Runnable> shutdownNow( )

• boolean isShutdown( )

• boolean isTerminated( )

• boolean awaitTermination(long timeout, TimeUnit unit)

Page 73: Java - Programmazione di Reti

ULezione 2: JAVA pooling 40Andrea Corradini

TERMINAZIONE DI EXECUTORS

• void shutdown( ): graceful termination.

non accetta ulteriori task

i tasks sottomessi in precedenza vengono eseguiti, compresi quelli la cui esecuzione non è ancora iniziata (quelli accodati).

tutti i threads del pool terminano la loro esecuzione

• List<Runnable> shutdowNow( ): immediate termination

non accetta ulteriori tasks,

elimina dalla coda i tasks la cui esecuzione non è ancora iniziata, e li restituisce in una lista

tenta di terminare l'esecuzione dei thread che stanno eseguendo i tasks (tipicamente con interrupt()): quindi non può garantire la terminazione dei thread.

Page 74: Java - Programmazione di Reti

ULezione 2: JAVA pooling 41Andrea Corradini

CALLABLE E FUTURE

• Un oggetto di tipo Runnable incapsula un'attività che viene eseguita in modo asincrono

• Una Runnable si può considerare un metodo asincrono, senza parametri e che non restituisce un valore di ritorno

• Per definire un task che restituisca un valore di ritorno occorre utilizzare le seguenti interfacce:– Callable: per definire un task che può restituire un risultato e sollevare

eccezioni– Future: per rappresentare il risultato di una computazione asincrona.

Definisce metodi per controllare se la computazione è terminata, per attendere la terminazione di una computazione (eventualmente per un tempo limitato),per cancellare una computazione, .....

• La classe FutureTask fornisce una implementazione della interfaccia Future.

Page 75: Java - Programmazione di Reti

ULezione 2: JAVA pooling 42Andrea Corradini

L'INTERFACCIA CALLABLE

public interface Callable<V>{ V call() throws Exception; }

L'interfaccia generica Callable<V>

• contiene il solo metodo call(), analogo al metodo run( ) della interfaccia Runnable, ma che può restituire un valore e sollevare eccezioni controllate

• per definire il codice deltask, occorre implementare il metodo call()

• il parametro di tipo <V> indica il tipo del valore restituito

• Esempio: Callable<Integer> rappresenta una elaborazione asincrona che restituisce un valore di tipo Integer

Page 76: Java - Programmazione di Reti

ULezione 2: JAVA pooling 43Andrea Corradini

CALLABLE: UN ESEMPIO

Definire un task T che calcoli una approssimazione di π, mediante la serie di Gregory-Leibniz (vedi lezione precedente). T restituisce il valore calcolato quando la differenza tra l'approssimazione ottenuta ed il valore di Math.PI risulta inferiore ad una soglia precision. T deve essere eseguito in un thread indipendente.

import java.util.concurrent.*;

public class Pigreco implements Callable<Double>{

private Double precision;

public Pigreco (Double precision) {this.precision = precision;};

public Double call ( ){ Double result = <calcolo dell'approssimazione di π>

return result; }}}

Page 77: Java - Programmazione di Reti

ULezione 2: JAVA pooling 44Andrea Corradini

L'INTERFACCIA FUTURE

• Per poter accedere al valore restituito dalla Callable, occorre costruire un

oggetto di tipo Future<V>, che rappresenta il risultato della computazione

• Per costruire un oggetto di tipo Future se si gestiscono esplicitamente i

threads:

– si costruisce un oggetto della classe FutureTask (che implementa Future

e Runnable) passando un oggetto di tipo Callable al costruttore

– si passa l'oggetto FutureTask al costruttore del thread

• Se si usano i thread pools, si sottomette direttamente l'oggetto di tipo

Callable al pool (con submit()) e si ottiene un oggetto di tipo Future

Page 78: Java - Programmazione di Reti

ULezione 2: JAVA pooling 45Andrea Corradini

L'INTERFACCIA FUTURE

public interface Future <V>{

V get( ) throws ...;

V get (long timeout, TimeUnit) throws ...;

void cancel (boolean mayInterrupt);

boolean isCancelled( );

boolean isDone( ); }

• get( ) si blocca fino alla terminazione del task e restituisce il valore calcolato

• È possibile definire un tempo massimo di attesa della terminazione del task, dopo cui viene sollevata una TimeoutException

• E' possibile cancellare il task e verificare se la computazione è terminata oppure è stata cancellata

Page 79: Java - Programmazione di Reti

ULezione 2: JAVA pooling 46Andrea Corradini

CALLABLE E FUTURE: UN ESEMPIO

import java.util.*;

import java.util.concurrent.*;

public class FutureCallable {

public static void main(String args[])

double precision = ........;

Pigreco pg = new Pigreco(precision);

FutureTask <Double> task= new FutureTask <Double>(pg);

Thread t = new Thread(task);

t.start();

Page 80: Java - Programmazione di Reti

ULezione 2: JAVA pooling 47Andrea Corradini

CALLABLE E FUTURE: UN ESEMPIO

try{

double ris = task.get(1000L, TimeUnit.MILLISECONDS);

System.out.println("valore di isdone" + task.isDone());

System.out.println(ris + "valore di pigreco");

}

catch(ExecutionException e) { e.printStackTrace();}

catch(TimeoutException e)

{ e.printStackTrace();

System.out.println("tempo scaduto");

System.out.println("valore di isdone" + task.isDone());}

catch(InterruptedException e){ } } }

Page 81: Java - Programmazione di Reti

ULezione 2: JAVA pooling 48Andrea Corradini

THREAD POOLING CON CALLABLE

• E' possibile sottomettere un oggetto di tipo Callable<V> ad un thread

pool mediante il metodo submit( )

• Il metodo restituisce direttamente un oggetto O di tipo Future<V>, per

cui non è necessario costruire oggetti di tipo FutureTask

• E' possibile applicare all'oggetto O tutti i metodi visti nei lucidi

precedenti

Page 82: Java - Programmazione di Reti

ULezione 2: JAVA pooling 49Andrea Corradini

THREAD POOLING CON CALLABLE

import java.util.*;

import java.util.concurrent.*;

public class futurepools {

public static void main(String args[])

ExecutorService pool = Executors.newCachedThreadPool ( );double precision = .........;

pigreco pg = new pigreco(precision);

Future <Double> result = pool.submit(pg);

try{ double ris = result.get(1000L, TimeUnit.MILLISECONDS);

System.out.println(ris+"valore di pigreco");}

catch(...........){ }..............}}

Page 83: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 1Andrea Corradini

Lezione n.3LPR-B-09

Threads: Sincronizzazione e Mutua Esclusione

6/10/2009Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 84: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 2Andrea Corradini

SULLA TERMINAZIONE: THREAD DEMONI

• Thread Demone (Daemon): fornisce un servizio, generalmente inbackground, fintanto che il programma è in esecuzione, ma non è considerato parte fondamentale di un programma

• Esempio: thread temporizzatori che scandiscono il tempo per conto di altri threads

• Quando tutti i thread non demoni hanno completato la lori esecuzione, il programma termina, anche se ci sono thread demoni in esecuzione

• Se ci sono thread non demoni in esecuzione, il programma non termina

Esempio: i thread attivati nel thread pool rimangono attivi anche se non esistono task da eseguire

• Si dichiara un thread demone invocando il metodo setdaemon(true), prima di avviare il thread

• Se un thread è un demone, allora anche tutti i threads da lui creati lo sono

Page 85: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 3Andrea Corradini

TERMINAZIONE: THREAD DEMONIpublic class SimpleDaemon extends Thread {

public SimpleDaemon ( ) {

setDaemon(true);

start( ); }

public void run( ) {

while(true) {

try {

sleep(100);

} catch (InterruptedException e) {

throw new RuntimeException(e);}

System.out.println("mi sono svegliato"+this); } }

Page 86: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 4Andrea Corradini

TERMINAZIONE: THREAD DEMONI

public static void main(String[ ] args) {for(int i = 0; i < 5; i++)

new SimpleDaemon( ); Thread.sleep(300);

} }

• il main crea 5 threads demoni

• ogni thread 'si addormenta' e si risveglia per un certo numero di volte, poi quando il main termina (non daemon thread), anche i threads terminano)

• Se pongo setDaemon(false) (il default), il programma non termina, i thread continuano ad 'addormentarsi' e 'risvegliarsi'.

Page 87: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 5Andrea Corradini

GRUPPI DI THREAD• Alcuni programmi contengono un gran numero di thread. Può essere utile

organizzare i thread in una struttura gerarchica in base alle loro funzionalità.

• Esempio: un browser attiva molti thread il cui compito è scaricare le immagini contenute in una pagina web. Se l'utente preme il pulsante stop(), è comodo utilizzare un metodo per interrompere tutti i threads simultaneamente.

• Gruppi di thread: sono insiemi di thread e di (sotto)gruppi di thread, raggruppati per esempio in base alle loro funzionalità, in modo che si possa lavorare su tutti threads di un gruppo simultaneamente.

ThreadGroup g = new ThreadGroup("GruppoPadre");ThreadGroup f = new ThreadGroup(g, "GruppoFiglio");Thread t1 = new Thread(g, aTask, "T1");Thread t2 = new Thread(g, anotherTask, "T2");............g.interrupt( ); // interrompe tutti i thread del gruppo

Page 88: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 6Andrea Corradini

CONDIVISIONE RISORSE TRA THREADS

• Più thread attivati da uno stesso programma possono condividere un insieme di oggetti. Schema tipico: gli oggetti vengono passati al costruttore del thread:

public class OggettoCondiviso { ........ }

public class Condivisione extends Thread {OggettoCondiviso oc;public Condivisione (OggettoCondiviso oc) {this.oc = oc;};public void run (){ ...... };

public static void main(String args[ ]){ OggettoCondiviso oc = new OggettoCondiviso();

new Condivisione(oc).start();

new Condivisione(oc).start(); }

}

Page 89: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 7Andrea Corradini

ACCESSO A RISORSE CONDIVISE

• L'interazione incontrollata dei threads sull'oggetto condiviso può produrre risultati non corretti

• Consideriamo il seguente esempio:

Definiamo una classe EvenValue che implementa un generatore di numeri pari.

Ogni oggetto istanza della classe ha un valore uguale ad un numero pari

Se il valore del numero è x, il metodo next( ), definito in EvenValueassegna il valore x+2

Si attivano un insieme di threads che condividono un oggetto di tipo EvenValue e che invocano concorrentemente il metodo next( )

Non si possono fare ipotesi sulla strategia di schedulazione dei threads

Page 90: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 8Andrea Corradini

ACCESSO A RISORSE CONDIVISE

public interface ValueGenerator {public int next( ); }

public class EvenValue implements ValueGenerator {

private int currentEvenValue = 0;

public int next( ) {++currentEvenValue;Thread.yield ( );++currentEvenValue;return currentEvenValue;}; }

Thread.yield ( ): “suggerisce” allo schedulatore di sospendere l'esecuzione del thread che ha invocato la yield( ) e di cedere la CPU ad altri threads

Page 91: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 9Andrea Corradini

ACCESSO A RISORSE CONDIVISEimport java.util.concurrent.*;

public class ThreadTester implements Runnable {

private ValueGenerator gen;

public ThreadTester(ValueGenerator gen) {this.gen = gen;}

public void run( ) {for (int i = 0; i < 5; i++){

int val= gen.next();if (val % 2 !=0) System.out.println(Thread.currentThread( )+"errore"+val);

else System.out.println(Thread.currentThread( )+"ok"+val); }}

public static void test(ValueGenerator gen, int count){ExecutorService exec= Executors.newCachedThreadPool();for (int i=0; i<count; i++){

exec.execute(new ThreadTester(gen));};

exec.shutdown( ); }}

Page 92: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 10Andrea Corradini

ACCESSO A RISORSE CONDIVISE

public class AccessTest {

public static void main(String args[ ]){EvenValue gen = new EvenValue();ThreadTester.test(gen, 2);} }

OUTPUT: Thread[pool-1-thread-1,5,main]ok2Thread[pool-1-thread-2,5,main]ok4Thread[pool-1-thread-1,5,main]errore7Thread[pool-1-thread-2,5,main]errore9Thread[pool-1-thread-1,5,main]ok10Thread[pool-1-thread-2,5,main]errore13Thread[pool-1-thread-1,5,main]ok14Thread[pool-1-thread-1,5,main]errore17Thread[pool-1-thread-2,5,main]ok18Thread[pool-1-thread-2,5,main]ok20

Page 93: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 11Andrea Corradini

RACE CONDITION

• Perchè si è verificato l'errore?

• Supponiamo che il valore corrente di currentEvenValue sia 0.

• Il primo thread esegue il primo assegnamento++currentEvenValue

e viene quindi deschedulato, in seguito alla yield( ): currentEvenValue assume valore 1

• A questo punto si attiva il secondo thread, che esegue lo stesso assegnamento e viene a sua volta deschedulato, currentEvenValue assume valore 2

• Viene riattivato il primo thread, che esegue il secondo incremento, il valore assume valore 3

• ERRORE! : Il valore restituito dal metodo next( ) è 3.

Page 94: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 12Andrea Corradini

RACE CONDITION e THREAD SAFETY

• Nel nostro caso la race condition (corsa critica) è dovuta alla possibilità che un thread invochi il metodo next( ) e venga deschedulato prima di avere completato l'esecuzione del metodo

• In questo modo la risorsa viene lasciata in uno stato inconsistente

(un solo incremento per currentEvenValue )

• Classi Thread Safe: l'esecuzione concorrente dei metodi definiti nella classe non provoca comportamenti scorretti

• EvenValue non è una classe thread safe

• Per renderla thread safe occorre garantire che le istruzioni contenute all'interno del metodo next( ) vengano eseguite in modo atomico o indivisibile o in mutua esclusione

Page 95: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 13Andrea Corradini

RACE CONDITION IN SINGOLA ISTRUZIONE• Race Condition: si può verificare anche nella esecuzione di una singola

istruzione di assegnamento

• Consideriamo un'istruzione che incrementa una variabile intera:count = count + 1; o count++;

• L'istruzione può essere elaborata come segue

1) il valore di count viene caricato in un registro

2) si somma 1

3) si memorizza il risultato in count

• Un thread T potrebbe eseguire i passi 1), 2) e poi venire deschedulato,

• Viene quindi schedulato un secondo thread Q che esegue tutta l'istruzione

• T esegue il passo 3) assegnando a count il valore che già contiene: un aggiornamento si è perso.

Page 96: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 14Andrea Corradini

Esercizio 1Si scriva un programma Java che dimostri che si possono verificare delle race conditions anche con una singola istruzione di incremento di una variabile.

Scrivere una classe Counter che offre un metodo next() che incrementa una variabile locale, e un metodo getCount() che ne restituisce il valore.

Scrivere un task TaskCounter che implementa Callable e che riceve nel costruttore un Counter e un intero n. Il task invoca la next() del Counter un numero casuale di volte compreso tra n/2 e n, e restituisce il numero casuale calcolato.

Il main crea un Counter e un pool di threads, in cui esegue M copie di TaskCounter passando a ognuna di esse il Counter e un valore N; quindi stampa la somma dei valori restituiti dagli M threads, e il valore finale del contatore ottenuto con getCount(): se questi due valori sono diversi c'è stata una race condition. M e N devono essere forniti dall'utente.

Page 97: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 15Andrea Corradini

RACE CONDITION: LAZY INITIALIZATION

Un altro esempio di una classe non thread safe

public class LazyInitRace {private ExpensiveObject instance = null;public ExpensiveObject getInstance( ){ if (instance == null)

instance = new ExpensiveObject(); return instance: }}

• Lazy Initialization =

alloca un oggetto solo se non esiste già un'istanza di quell'oggetto

deve assicurare che l'oggetto venga inizializzato una sola volta

getInstance( ) deve restituire sempre la stessa istanza

Page 98: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 16Andrea Corradini

RACE CONDITIONS: ESEMPIpublic class LazyInitRace {

private ExpensiveObject instance = null;public ExpensiveObject getInstance( ){ if (instance == null)

instance = new ExpensiveObject(); return instance: }}

• Il programma non è corretto perchè contiene una race condition

• Il thread A esegue getInstance(), trova (instance == null), poi viene deschedulato. Il thread B esegue getInstance() e trova a sua volta (instance == null). I due thread restituiscono due diverse istanze di ExpensiveObject

Page 99: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 17Andrea Corradini

JAVA: MECCANISMI DI LOCK

• Occorre disporre di meccanismi per garantire che un metodo (es: next())

venga eseguito in mutua esclusione quando invocato su di un oggetto

• JAVA offre un meccanismo implicito di locking (intrinsic locks) che

consente di assicurare la atomicità di porzioni di codice eseguite in modo

concorrente sullo stesso oggetto

• L'uso del lock garantisce che se un thread T esegue un metodo di istanza

di un oggetto, nessun altro thread che richiede il lock può eseguire un

metodo sullo stesso oggetto fino a che T non ha terminato l'esecuzione

del metodo

Page 100: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 18Andrea Corradini

JAVA: IL COMANDO synchronized

• Sincronizzazione di un blocco:

synchronized (obj)

{ // blocco di codice che accede o modifica l'oggetto

}

• L'oggetto obj può essere quello su cui è stato invocato il metodo che contiene il codice (this) oppure un altro oggetto

• Il thread che esegue il blocco sincronizzato deve acquisire il locksull'oggetto obj

• Il lock viene rilasciato nel momento in cui il thread termina l'esecuzione del blocco (es: return, throw, esecuzione dell'ultima istruzione del blocco)

Page 101: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 19Andrea Corradini

JAVA: RENDERE ATOMICO IL METODO NEXT

public class EvenGenerator implements ValueGenerator{

private int currentEvenValue = 0;

public int next( ){synchronized(this){

++currentEvenValue;Thread.yield();++currentEvenValue;return currentEvenValue;} } }

• Questa modifica consente di evitare le race conditions

• ATTENZIONE: in generale non è consigliabile l'inserimento di una istruzione che blocca il thread che la invoca (sleep( ), yield( ),....) all'interno di un blocco sincronizzato

• Infatti il thread che si blocca non rilascia il lock ed impedisce ad altri threads di invocare il metodo next( ) sullo stesso oggetto

Page 102: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 20Andrea Corradini

JAVA 1.5: LOCK ESPLICITI

• A partire da JAVA 1.5 è possibile definire ed utilizzare oggetti di tipo lock

import java.util.concurrent.locks.*;

class X { private final ReentrantLock mylock = new ReentrantLock( );// ..public void m( ) {

mylock.lock( ); // block until condition holds

try { // ... method body

} finally {lock.unlock( ) } } }

Page 103: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 21Andrea Corradini

JAVA 1.5: LOCK ESPLICITI• Vediamo un'altra versione del nostro esempio con lock esplicito:

import java.util.concurrent.locks.*;

public class LockingEvenGenerator implements ValueGenerator {

private int currentEvenValue = 0;

ReentrantLock evenlock=new ReentrantLock( );

public int next( ) {try {

evenlock.lock( );++currentEvenValue;Thread.yield ( );++currentEvenValue;return currentEvenValue;

} finally {evenlock.unlock( );}}}

Page 104: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 22Andrea Corradini

JAVA: MECCANISMO DEI LOCK

• Lock espliciti: si definisce un oggetto di tipo ReentrantLock( ) Quando un thread invoca il metodo lock( ) su un oggettodi tipo

ReentrantLock( ), il thread rimane bloccato se qualche altro thread ha già acquisito il lock

Quando un thread invoca unlock( ) uno dei thread eventualmente bloccati su quella lock viene risvegliato

• Lock impliciti su metodi

Sono definiti associando al metodo la parola chiave synchronized

Equivale a sincronizzare tutto il blocco di codice che corrisponde al corpo del metodo

L'oggetto su cui si acquisisce il lock è quello su cui viene invocato il metodo

Page 105: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 23Andrea Corradini

I METODI SYNCHRONIZED

• La parola chiave synchronized nella intestazione di un metodo ha l'effetto di serializzare gli accessi al metodo

public synchronized int next ( )

• Se un thread sta eseguendo il metodo next( ), nessun altro thread potrà

eseguire lo stesso codice sullo stesso oggetto finchè il primo thread non

termina l'esecuzione del metodo

• Implementazione:

Supponiamo che il metodo m synchronized appartenga alla classe C

ad ogni oggetto O istanza di C viene associata un lock, L(O)

quando un thread T invoca m su O, T tenta di acquisire L(O), prima di iniziare l'esecuzione di M. Se T non acquisisce L(O), si sospende

Page 106: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 24Andrea Corradini

I METODI SYNCHRONIZED

• Se rendiamo synchronized il metodo next(), l'output che otteniamo sarà

Thread[pool-1-thread-1,5,main]ok2

Thread[pool-1-thread-2,5,main]ok4

Thread[pool-1-thread-1,5,main]ok6

Thread[pool-1-thread-2,5,main]ok8

Thread[pool-1-thread-1,5,main]ok10

Thread[pool-1-thread-2,5,main]ok12

Thread[pool-1-thread-1,5,main]ok14

Thread[pool-1-thread-2,5,main]ok16

Thread[pool-1-thread-1,5,main]ok18

Thread[pool-1-thread-2,5,main]ok20

Page 107: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 25Andrea Corradini

I METODI SYNCHRONIZED

• Importante: il lock è associato all'istanza di un oggetto, non al metodo o alla classe (a meno di metodi statici che vedremo in seguito)

• Diversi metodi sincronizzati invocati sull'istanza dello stesso oggetto competono per lo stesso lock, quindi risultano mutuamente esclusivi

• Metodi sincronizzati che operano su istanze diverse dello stesso oggetto possono essere eseguiti in modo concorrente

• All'interno della stessa classe possono comparire contemporaneamente metodi sincronizzati e non (anche se raramente)

I metodi non sincronizzati possono essere eseguiti in modo concorrente

In ogni istante, su un certo oggetto, possono essere eseguiti concorrentemente più metodi non sincronizzati e solo uno dei metodi sincronizzati della classe

Page 108: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 26Andrea Corradini

I METODI SYNCHRONIZEDL'esempio seguente crea due istanze dell'oggetto EvenValue1( ) e le passa a due thread distinti. Si considera la versione non sincronizzata del metodo next( )

public class EvenValue1 implements ValueGenerator{

private int currentEvenValue = 0;

public int next( ){ ++currentEvenValue; ++currentEvenValue;return currentEvenValue; } }

public class SynchroTest {public static void main(String args[ ]){ValueGenerator eg1 = new EvenValue1();ValueGenerator eg2 = new EvenValue1();ThreadTester1.test(eg1,eg2);}}

Page 109: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 27Andrea Corradini

I METODI SYNCHRONIZEDimport java.util.concurrent.*;

import java.util.Random;

public class ThreadTester1 implements Runnable{private ValueGenerator g;public ThreadTester1 (ValueGenerator g) {this.g = g;}public void run( ){

for (int i=0; i<5; i++){int val= g.next();if (val % 2 !=0)System.out.println(Thread.currentThread() + "errore" + val);else System.out.println(Thread.currentThread() + "ok" + val);try {Thread.sleep((int) Math.random() * 1000);} catch (Exception e) { }; }}

Page 110: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 28Andrea Corradini

I METODI SYNCHRONIZED

public static void test(ValueGenerator g1, ValueGenerator g2){ExecutorService exec= Executors.newCachedThreadPool();exec.execute(new tester(g1));exec.execute(new tester(g2)); exec.shutdown() } }

OUTPUT: il risultato è corretto anche se next() non è sincronizzatoThread[pool-1-thread-1,5,main]ok2

Thread[pool-1-thread-2,5,main]ok2

Thread[pool-1-thread-2,5,main]ok4

Thread[pool-1-thread-2,5,main]ok6

Thread[pool-1-thread-2,5,main]ok8

Thread[pool-1-thread-2,5,main]ok10

Thread[pool-1-thread-1,5,main]ok4

Thread[pool-1-thread-1,5,main]ok6

Thread[pool-1-thread-1,5,main]ok8

Thread[pool-1-thread-1,5,main]ok10

Page 111: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 29Andrea Corradini

Esercizio 2

• Si consideri il metodo next() della classe Counter dell'Esercizio 1. Modificarlo in modo da renderne l'esecuzione non interrompibile, e rieseguire il programma verificando che non si verificano più race conditions. Fare questo nei tre modi visti: usando un comando synchronized usando un lock esplicito dichiarando synchronized il metodo next()

Page 112: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 30Andrea Corradini

LOCK RIENTRANTI

• I lock intrinsechi di JAVA sono rientranti, ovvero il lock( ) su un oggetto O viene associato al thread che accede ad O.

• se un thread tenta di acquisire un lock che già possiede, la sua richiesta ha successo

• Ovvero... un thread può invocare un metodo sincronizzato m su un oggetto O e all'interno di m vi può essere l'invocazione ad un altro metodo sincronizzato su O e così via

• Il meccanismo dei lock rientranti favorisce la prevenzione di situazioni di deadlock

Page 113: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 31Andrea Corradini

LOCK RIENTRANTI

• Implementazione delle lock rientranti

Ad ogni lock viene associato un contatore ed un identificatore di thread

Quando un thread T acquisisce un lock, la JVM alloca una struttura che contiene l'identificatore T e un contatore, inizializzato a 0

Ad ogni successiva richiesta dello stesso lock, il contatore viene incrementato mentre viene decrementato quando il metodo termina

• Il lock( ) viene rilasciato quando il valore del contatore diventa 0

Page 114: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 32Andrea Corradini

REENTRANT LOCK E EREDITARIETA'

public class ReentrantExample {

public synchronized void doSomething( ) {

.............} }

public class ReentrantExtended extends ReentrantExample{

public synchronized void doSomething( ){System.out.println(toString( ) + ": chiamata a doSomething");super.doSomething();} }

• La chiamata super.doSomething( ) si bloccherebbe se il lock non fosse rientrante, ed il programma risulterebbe bloccato (deadlock)

Page 115: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 33Andrea Corradini

MUTUA ESCLUSIONE: RIASSUNTO

• Interazione implicita tra diversi threads: i thread accedono a risorse condivise.

• Per mantenere consistente l’oggetto condiviso occorre garantire la mutua esclusione su di esso.

• La mutua esclusione viene garantita associando un lock ad ogni oggetto

• I metodi synchronized garantiscono che un thread per volta possa eseguire un metodo sull'istanza di un oggetto e quindi garantiscono lamutua esclusione sull’oggetto

Page 116: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 34Andrea Corradini

ESERCIZIO 3: ANCORA RACE CONDITIONSSimulare il comportamento di una banca che gestisce un certo numero di conti

correnti. In particolare interessa simulare lo spostamento di denaro tra due

conti correnti.

Ad ogni conto è associato un thread T che implementa un metodo che consente

di trasferire una quantità casuale di denaro tra il conto servito da T ed un

altro conto il cui identificatore è generato casualmente.

• sviluppare una versione non thread safe del programma in modo da evidenziare un comportamento scorretto del programma

• definire 3 versioni thread safe del programma che utilizzino, rispettivamente

Lock esplicite

Blocchi sincronizzati

Metodi sincronizzati

Page 117: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 35Andrea Corradini

THREADS COOPERANTI: I MONITOR

• L'interazione esplicita tra threads avviene in un linguaggio ad oggetti come JAVA mediante l'utilizzo di oggetti condivisi

• Esempio: produttore/consumatore il produttore P produce un nuovo valore e lo comunica ad un thread consumatore C

• Il valore prodotto viene incapsulato in un oggetto condiviso da P e da C, ad esempio una coda che memorizza i messaggi scambiati tra P e C

• La mutua esclusione sull'oggetto condiviso è garantita dall'uso di metodi synchronized, ma...non è sufficiente garantire sincronizzazioni esplicite

• E' necessario introdurre costrutti per sospendere un thread T quando una condizione C non è verificata e per riattivare T quando diventa vera

• Esempio: il produttore si sospende se il buffer è pieno, si riattiva quando

c'e' una posizione libera

Page 118: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 36Andrea Corradini

• Monitor = Classe di oggetti utilizzabili da un insieme di threads

• Come ogni classe, il monitor ha un insieme di campi ed un insieme di metodi

• La mutua esclusione può essere garantita dalla definizione di metodi synchronized. Un solo thread per volta si “all'interno del monitor”

• E' necessario inoltre

definire un insieme di condizioni sullo stato dell'oggetto condiviso

implementare meccanismi di sospensione/riattivazione dei threads sulla base del valore di queste condizioni

Implementazioni possibili: • definizione di variabili di condizione• metodi per la sospensione su queste variabili• definizione di code associate alle variabili in cui memorizzare i

threads sospesi

THREADS COOPERANTI: I MONITOR

Page 119: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 37Andrea Corradini

JAVA ● non supporta variabili di condizione● assegna al programmatore il compito di gestire le condizioni

mediante variabili del programma● definisce meccanismi che consentono ad un thread

● di sospendersi wait( ) in attesa che sia verificata una condizione

● di segnalare con notify( ), notifyall ( ) ad un altro/ad altri threads sospesi che una certa condizione è verificata

● Per ogni oggetto implementa due code:● una coda per i thread in attesa di acquisire il lock● una coda in cui vengono memorizzati tutti i thread sospesi con

la wait( ) (in attesa del verificarsi di una condizione).

THREADS COOPERANTI: I MONITOR

Page 120: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 38Andrea Corradini

CAMPI DELL'OGGETTO

Metodo sincronizzato

Metodo non sincronizzato..

.

.Coda dei threads in

attesa del verificarsi di una condizione (con wait())

MONITOR

Coda dei threads inattesa della lock

.

.

.

.

THREADS COOPERANTI: I MONITOR

Page 121: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 39Andrea Corradini

ESEMPIO: PRODUTTORE/CONSUMATORE

• Produttore/Consumatore: due thread si scambiano dati attraverso un oggetto condiviso buffer

• Ogni thread deve acquisire il lock sull'oggetto buffer, prima di inserire/prelevare elementi

• Una volta acquisito il lock

il consumatore controlla se c'è almeno un elemento nel buffer: • in caso positivo, preleva un elemento dal buffer e risveglia

l'eventuale produttore in attesa;• se il buffer è vuoto si sospende,

il produttore controlla se c'è almeno una posizione libera nel buffer:• in caso positivo, inserisce un elemento nel buffer e risveglia

l'eventuale consumatore in attesa,• se il buffer è pieno si sospende.

Page 122: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 40Andrea Corradini

I METODI WAIT/NOTIFY

Metodi d'istanza invocati sull'oggetto condiviso (se non compare il riferimento

all'oggetto, ovviamente l'oggetto implicito riferito è this)

• void wait( ) sospende il thread sull'oggetto

• void wait(long timeout) sospende per al massimo timeout millisecondi

• void notify( ) risveglia un thread in attesa sull'oggetto

• void notifyall( ) risveglia tutti i threads in attesa sull'oggetto

Tutti questi metodi

sono definiti nella classe Object (tutti le classi ereditano da Object,....)

per invocare questi metodi occorre aver acquisito il lock sull'oggetto, altrimenti viene lanciata una IllegalMonitorStateException. Quindi vanno invocati all'interno di un metodo o di un blocco sincronizzato, o dopo aver acquisito un lock eslpicito.

Page 123: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 41Andrea Corradini

WAIT, NOTIFY E IL LOCK

wait( )

rilascia il lock sull'oggetto prima di sospendere il thread corrente

quando risvegliato da una notify( ), il thread compete per riacquisire il lock

notify( )

risveglia uno dei thread (non si sa quale...) nella coda di attesa dell'oggetto; non rilascia immediatamente il lock

notifyAll( )

risveglia tutti i threads in attesa sull'oggetto; non rilascia il lock

Tutti i thread risvegliati competono per l'acquisizione del lock sull'oggetto, e verranno eseguiti uno alla volta, quando riusciranno a riacquisire il lock.

Page 124: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 42Andrea Corradini

WAIT E NOTIFY

• Il metodo wait() permette di attendere il cambiamento di una condizione sullo stato dell'oggetto “fuori dal monitor”, in modo passivo

• Evita il controllo ripetuto di una condizione (polling)

• A differenza di sleep() e di yield() rilascia il lock sull'oggetto

• Quando ci si sospende su di una condizione, occorre controllarla quando si viene risvegliati:

synchronized(obj){while (<condizione non soddisfatta>)

obj.wait();... // esegui l'azione per cui richiedevi la condizione

}

• L'invocazione di un metodo wait(), notify(), notifyall() fuori da un metodo synchronized solleva l'eccezione IllegalMonitorException( ): prima di invocare questi metodi occorre aver acquisito il lock su un oggetto condiviso

Page 125: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 43Andrea Corradini

PRODUTTORE/CONSUMATORE: IL BUFFER

public class Buffer {

int[] buffer; int size = 0; // Array Parzialmente Riempito

public Buffer(int capacity){ buffer = new int[capacity]; }

public synchronized int get() throws InterruptedException{while (size == 0) wait();int result = buffer[--size]; // restituisce l'ultimo notify(); // elemento inseritoreturn result; }

public synchronized void put(int n) throws InterruptedException{while (size == buffer.length) wait();buffer[size++] = n;notify(); } }

Page 126: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 44Andrea Corradini

IL PRODUTTOREpublic class Producer implements Runnable {

private Buffer buf;

public Producer(Buffer buf){ this.buf = buf; }

public void run() {try{

while(true){int next = (int)(Math.random() * 10000);buf.put(next);System.out.println("[Producer] Put " + next);Thread.sleep((int)(Math.random() * 500)); }

} catch (InterruptedException e){System.out.println("[Producer] Interrupted");

} } }

Page 127: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 45Andrea Corradini

IL CONSUMATORE

public class Consumer implements Runnable {

private Buffer buf;

public Consumer(Buffer buf){ this.buf = buf; }

public void run() {try{

while(true){System.out.println("[Consumer] Got " + buf.get());Thread.sleep((int)(Math.random() * 500)); }

}catch (InterruptedException e){System.out.println("[Consumer] Interrupted");

} } }

Page 128: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 46Andrea Corradini

PRODUTTORE/CONSUMATORE: IL MAIN

import java.util.concurrent.*;

public class TestProducerConsumer {

public static void main(String[] args) {

Buffer buf = new Buffer(5);

Consumer cons = new Consumer(buf);

Producer prod = new Producer(buf);

ExecutorService exec = Executors.newFixedThreadPool(2);

exec.execute(cons);

exec.execute(prod);

try { Thread.sleep(10000); } catch (InterruptedException e) { }

exec.shutdownNow();

} }

Page 129: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 47Andrea Corradini

PRODUCER/CONSUMER: OUTPUT

Esempio di output del programma:[Consumer] Got 7493[Producer] Put 7493[Producer] Put 4495[Consumer] Got 4495[Producer] Put 1515[Producer] Put 8502[Consumer] Got 8502[Producer] Put 4162[Producer] Put 954[Producer] Put 880[Consumer] Got 880[Producer] Put 8503[Producer] Put 4980[Consumer] Got 4980[Consumer] Got 8503[Producer] Put 3013[Consumer] Got 3013[Consumer] Interrupted[Producer] Interrupted

• Si noti che poiché il buffer ha una politica Last In First Out (LIFO), l'ordine non viene preservato. Per esempio, il numero 1515 non viene mai estratto dal buffer.

Page 130: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 48Andrea Corradini

ESERCIZIO 4

• La classe Buffer ha una politica Last In First Out (LIFO), quindi non preserva l'ordine. Scrivere la classe CircularBuffer che estende Buffer e realizza una politica FIFO, gestendo l'array in modo circolare.

• Definire le interfacce generiche Producer<E>, Consumer<E> e Buffer<E>, che definiscono un sistema produttore/consumatore per un generico tipo di dati E.

• Implementare le interfacce in modo che il produttore produca una sequenza di stringhe, leggendole da un file passato come parametro al task, e il consumatore scriva le stringhe che prende dal buffer in un altro file.

• Nel main, creare e attivare un produttore e due o più consumatori. Verificare che la concatenazione dei file generati dai consumatori sia uguale, a meno dell'ordine delle righe, al file letto dal produttore.

Page 131: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 49Andrea Corradini

ESERCIZIO 5 (a)

Il laboratorio di Informatica del Polo Marzotto è utilizzato da tre tipi di utenti, studenti, tesisti e professori ed ogni utente deve fare una richiesta al tutor per accedere al laboratorio. I computers del laboratorio sono numerati da 1 a 20. Le richieste di accesso sono diverse a seconda del tipo dell'utente:

a) i professori accedono in modo esclusivo a tutto il laboratorio, poichè hanno necessità di utilizzare tutti i computers per effettuare prove in rete.

b) i tesisti richiedono l'uso esclusivo di un solo computer, identificato dall'indice i, poichè su quel computer è istallato un particolare software necessario per lo sviluppo della tesi.

c) gli studenti richiedono l'uso esclusivo di un qualsiasi computer.

I professori hanno priorità su tutti nell'accesso al laboratorio, i tesisti hanno priorità sugli studenti. (prosegue nella pagina successiva)

Page 132: Java - Programmazione di Reti

ULezione 3: Threads: Sincronizzazione e Mutua Esclusione 50Andrea Corradini

ESERCIZIO 5(b)

Scrivere un programma JAVA che simuli il comportamento degli utenti e del tutor. Il programma riceve in ingresso il numero di studenti, tesisti e professori che utilizzano il laboratorio ed attiva un thread per ogni utente. Ogni utente accede k volte al laboratorio, con k generato casualmente. Simulare l'intervallo di tempo che intercorre tra un accesso ed il successivo e l'intervallo di permanenza in laboratorio mediante il metodo sleep. Il tutor deve coordinare gli accessi al laboratorio. Il programma deve terminare quando tutti gli utenti hanno completato i loro accessi al laboratorio.

Page 133: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 1Vincenzo Gervasi

Lezione n.4LPR-A-09

Indirizzi IP e URL

13/10/2009Vincenzo Gervasi

Università degli Studi di Pisa Dipartimento di Informatica

Page 134: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 2Vincenzo Gervasi

PROGRAMMAZIONE DI RETE: INTRODUZIONEProgrammazione di rete:

sviluppare applicazioni definite mediante due o più processi in esecuzione

su hosts diversi, distribuiti sulla rete. I processi cooperano per realizzare

una certa funzionalità Cooperazione: richiede lo scambio di informazioni (comunicazione) tra i

processi Comunicazione = Utilizza protocolli (cioè insieme di regole che i partners

della comunicazione devono seguire per poter comunicare) Alcuni protocolli utilizzati in INTERNET:

– IP (Internet Protocol)– TCP (Transmission Control Protocol) un protocollo connection-oriented– UDP (User Datagram Protocol) protocollo connectionless

Page 135: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 3Vincenzo Gervasi

PROGRAMMAZIONE DI RETE: INTRODUZIONE

Per identificare un processo con cui si vuole comunicare occorre conoscere:

• la rete in cui si trova l’host su cui e’ in esecuzione il processo• l’host all’interno della rete• il processo in esecuzione sull’host

– Identificazione della rete e dell'host• definita dal protocollo IP (Internet Protocol)

– Identificazione del processo• utilizza il concetto di porta

– Porta• Intero da 0 a 65535

Page 136: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 4Vincenzo Gervasi

IL PROTOCOLLO IP

Il Protocollo IP (Internet Protocol) definisce

• un sistema di indirizzamento per gli hosts

• la definizione della struttura del pacchetto IP

• un insieme di regole per la spedizione/ricezione dei pacchetti

Due versioni del protocollo IP sono attualmente utilizzate in Internet:

• IPV4 (IP Versione 4)

• IPV6 (IP versione 6)

– IPV6 introduce uno spazio di indirizzi di dimensione maggiore rispetto a IPV4 (i cui indirizzi cominciano a scarseggiare...)

– Di uso ancora limitato

Page 137: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 5Vincenzo Gervasi

INDIRIZZAMENTO DEGLI HOSTS

Materiale di riferimento: Pitt, capitolo 2 Ogni host di una rete IPV4 o IPV6 è connesso alla rete mediante una o

più interfacce Ogni interfaccia è caratterizzata da un indirizzo IP Indirizzo IP

− IPV4: numero rappresentato su 32 bits (4 bytes)− IPV6:numero rappresentato su 128 bits (16 bytes)

Multi-homed host: un host che possiede un insieme di interfacce verso la rete, e quindi un insime di indirizzi IP (uno per ogni interfaccia)– gateway tra sottoreti IP− routers

Page 138: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 6Vincenzo Gervasi

INDIRIZZI IP

Un indirizzo IPV4

32 bits Ognuno dei 4 bytes, viene interpretato come un numero decimale

senza segno Rappresentato come sequenza di 4 valori da 0 a 255 separati da “.”

Un indirizzo IPV6 128 bits sequenza di 8 gruppi di 4 cifre esadecimali, separati da “:”, es.

2000:fdb8:0000:0000:0001:00ab:853c:39a12000:fdb8::1:00ab:853c:39a1

10010001 00001010 00100010 00000011

145. 10. 34. 3

Page 139: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 7Vincenzo Gervasi

INDIRIZZI IP E NOMI DI DOMINIO

• Gli indirizzi IP sono indispensabili per la funzionalità di istradamento dei pacchetti effettuata dai routers, ma sono poco leggibili per gli utenti della rete

• Soluzione: assegnare un nome simbolico (unico?) a ogni host si utilizza uno spazio di nomi gerarchico, per esempio:

fujih1.cli.di.unipi.it (host fujih1 nel dominio cli.di.unipi.it ) livelli della gerarchia separati dal punto. nomi interpretati da destra a sinistra

• Risoluzione di indirizzi IP: corrispondenza tra nomi ed indirizzi IP

• La risoluzione viene gestita da un servizio di nomi (“servizio DNS”) DNS = Domain Name System

Page 140: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 8Vincenzo Gervasi

INDIRIZZAMENTO A LIVELLO DI PROCESSI

• Su ogni host possono essere attivi contemporaneamente più servizi (es: e-mail, ftp, http,…)

• Ogni servizio viene incapsulato in un diverso processo• L’indirizzamento di un processo avviene mediante una porta• Porta = intero compreso tra 0 e 65535. Non è un dispositivo fisico, ma

un'astrazione per individuare i singoli servizi (processi).• Porte comprese tra 1 e 1023 riservati per particolari servizi. • In Linux: solo i programmi in esecuzione con diritti di root possono

ricevere dati da queste porte. Chiunque può inviare dati a queste porte.Esempi: porta 7 echo porta 21 ftp

porta 22 ssh porta 32 telnet porta 80 HTTP

• In LINUX: controllare il file /etc/services

Page 141: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 9Vincenzo Gervasi

SOCKETS

• Socket: astrae il concetto di 'communication endpoint'

• Individuato da un indirizzo IP e da un numero di porta

• Socket in JAVA: istanza di una di queste classi (che vedremo in futuro)

– Socket

– ServerSocket

– DatagramSocket

– MulticastSocket

Page 142: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 10Vincenzo Gervasi

JAVA: LA CLASSE INETADDRESSpublic static InetAddress [ ] getAllByName (String hostname)

throws UnKnownHostException

utilizzata nel caso di hosts che posseggano piu indirizzi (es: web servers)

public static InetAddress getLocalHost () throws UnKnownHostException

per reperire nome simbolico ed indirizzo IP del computer locale

Getter Methods = Per reperire i campi di un oggetto di tipo InetAddress

public String getHostName ( ) // può fare una reverse resolution

r

public byte [ ] getAddress ( )

public String getHostAddress ( )

Page 143: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 11Vincenzo Gervasi

JAVA: LA CLASSE INETADDRESS

public static InetAddress getByName (String hostname) throws UnKnownHostException

se il valore di hostname è l’indirizzo IP (una stringa che codifica la

dotted form dell'indirizzo IP)

la getByName non contatta il DNS il nome dell’host non viene impostato nell'oggetto InetAddress il DNS viene contattato solo quando viene richiesto esplicitamente il

nome dell’host tramite il metodo getter getHostName( ) la getHostName( ) non solleva eccezione, se non riesce a risolvere

l’indirizzo IP.

Page 144: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 12Vincenzo Gervasi

JAVA: LA CLASSE INETADDRESS

• accesso al DNS: operazione potenzialmente molto costosa

• i metodi descritti effettuano caching dei nomi/indirizzi risolti.

• nella cache vengono memorizzati anche i tentativi di risoluzione non andati a buon fine (di default: per un certo numero di secondi)

• se creo un InetAddress per lo stesso host, il nome viene risolto con i dati nella cache (di default: per sempre)

• permanenza dati nella cache: per default alcuni secondi se la risoluzione non ha avuto successo, illimitato altrimenti. Problemi: indirizzi dinamici..

• java.security.Security.setProperty consente di impostare il numero di secondi in cui una entry nella cache rimane valida, tramite le proprietà

networkaddress.cache.ttl e networkaddress.cache.negative.ttl

esempio:

java.security.Security.setProperty("networkaddress.cache.ttl" , "0");

Page 145: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 13Vincenzo Gervasi

LA CLASSE INETADDRESS:ESEMPIO DI UTILIZZO

• implementazione in JAVA della utility UNIX nslookup

• nslookup

consente di tradurre nomi di hosts in indirizzi IP e viceversa

i valori da tradurre possono essere forniti in modo interattivo oppure da linea di comando

si entra in modalità interattiva se non si forniscono parametri da linea di comando

consente anche funzioni più complesse (vedere LINUX)

Page 146: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 14Vincenzo Gervasi

LA CLASSE INETADDRESS:ESEMPIO DI UTILIZZO

import java.net.*;import java.io.*;

public class HostLookUp {public static void main (String [ ] args) {if (args.length > 0) { for (int i=0; i<args.length; i++) {

System.out.println (lookup(args[i])) ;}

}else {/* modalita’ interattiva*/ }

Page 147: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 15Vincenzo Gervasi

LA CLASSE INETADDRESS:ESEMPIO DI UTILIZZO

private static boolean isHostName (String host){

char[ ] ca = host.toCharArray(); for (int i = 0; i < ca.length; i++) {

if(!Character.isDigit(ca[i])) {if (ca[i] != '.')

return true; }

}return false;

}

Page 148: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 16Vincenzo Gervasi

LA CLASSE INETADDRESS:ESEMPIO DI UTILIZZO

private static String lookup(String host) {InetAddress node;try {

node = InetAddress.getByName(host); System.out.println(node); if (isHostName(host))

return node.getHostAddress( );else

return node.getHostName ( ); } catch (UnknownHostException e)

return "non ho trovato l’host"; }

Page 149: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 17Vincenzo Gervasi

Esercizio 1

• Scrivere un programma Java Resolve che traduca una sequenza di nomi simbolici di host nei corrispondenti indirizzi IP.

• Resolve legge i nomi simbolici da un file, il cui nome è passato da linea di comando oppure richiesto all'utente.

• Si deve definire un task che estenda l’interfaccia Callable, e che, ricevuto come parametro un nome simbolico, provvede a tradurre il nome ritornando un InetAddress.

• Per ottimizzare la ricerca, si deve attivare un pool di thread che esegua i task in modo concorrente. Ogni volta che si sottomette al pool di thread un task, si ottiene un oggetto Future<InetAddress>, che deve essere aggiunto ad un ArrayList.

• Infine, si scorre l’ArrayList, stampando a video gli InetAddress.

Page 150: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 18Vincenzo Gervasi

• Scrivere un programma che enumeri e stampi a video tutte le interfacce di rete del computer, usando i metodi della classe java.net.NetworkInterface.

• Usare il metodo statico getNetworkInterfaces() per ottenere una Enumeration di NetworkInterface.

• Per ogni NetworkInterface, stampare gli indirizzi IP associati ad essa (IPv4 e IPv6) e il nome dell’interfaccia.

Esercizio 2

Page 151: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 19Vincenzo Gervasi

• Scrivere un programma che ricerca una parola chiave (key) nei file contenuti in una directory (fornita dall'utente) e nelle sue sottodirectory. Per ogni file che contiene key, si deve visualizzare il nome dei file e il contenuto della prima riga trovata che contiene key.

• Creare una classe FindKeyword che implementa Callable, alla quale si può passare una directory come parametro del costruttore, e che ritorna un array di stringhe del formato

<nome file> : <contenuto riga che contiene key>

• Il metodo search della classe FindKeyword implementa la ricerca di key all’interno di un singolo file, e ritorna una stringa formattata come sopra oppure null se key non compare.

• Creare un pool di thread a cui vengono sottomessi un task FindKeyword per ogni directory/sottodirectory, e usare gli oggetti Future restituiti per stampare a video i risultati ottenuti.

Esercizio 3

Page 152: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 20Vincenzo Gervasi

Uniform Resource Locator

• URL è un acronimo per Uniform Resource Locator• Un riferimento (un indirizzo) per una risorsa su Internet.

Di solito un URL è il nome di un file su un host. Ma può anche puntare ad altre risorse:

una query per un database;l’output di un comando.

Es: http://java.sun.comhttp: identificativo del protocollo.java.sun.com: nome della risorsa.

Page 153: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 21Vincenzo Gervasi

Nomi di risorsa

• Il nome di una risorsa è composto da: Host Name: il nome dell’host su cui si trova la risorsa. Filename: il pathname del file sull’host. Port Number: il numero della porta su cui connettersi

(opzionale). Reference: un riferimento ad una specifica locazione

all’interno del file (opzionale).• Nel caso del protocollo http, se il Filename è omesso (o

finisce per /), il web server è configurato per restituire un file di default all’interno del path (ad es. index.html, index.php, index.asp).

Page 154: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 22Vincenzo Gervasi

URL e URI

• Un URI (Uniform Resource Identifier) è un costrutto sintattico che specifica, tramite le varie parti che lo compongono, una risorsa su Internet: [schema:]ParteSpecificaSchema[#frammento] dove ParteSpecificaSchema ha la struttura

[//autorita’][percorso][?query]

• Un URL è un tipo particolare di URI: contiene sufficienti informazioni per individuare e ottenere una risorsa.

• Altre URI, ad es: URN:ISBN:0-395-36341-1 non specificano come individuare la risorsa. In questo caso, le URI sono dette URN (Uniform Resource

Name).

Page 155: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 23Vincenzo Gervasi

URL in Java

• In JAVA per creare un oggetto URL: URL cli = new URL(“http://www.cli.di.unipi.it/”); è un esempio di un URL assoluto.

• È anche possibile creare un URL relativo, che ha la forma URL(URL baseURL, String relativeURL) Esempi:.

URL cli = new URL(“http://www.cli.di.unipi.it/”);URL faq = new URL(cli, “faq”);

che risulterà puntare a http://www.cli.di.unipi.it/faq• I protocolli gestiti da Java con gli URL sono http, https, ftp, file e jar.• I costruttori possono lanciare una MalformedURLException.

Page 156: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 24Vincenzo Gervasi

Parsare un URL

• La classe URL offre metodi per accedere ai componenti di una URLimport java.net.*;import java.io.*;

public class URLReader {public static void main(String[] args) throws Exception {

String url = “http://www.cli.di.unipi.it:80/faq”;URL cli = new URL(url);System.out.println(“protocol = ” + cli.getProtocol());System.out.println(“authority = ” + cli.getAuthority());System.out.println(“host = ” + cli.getHost());System.out.println(“port = ” + cli.getPort());System.out.println(“path = ” + cli.getPath());System.out.println(“query = ” + cli.getQuery());System.out.println(“filename = ” + cli.getFile());System.out.println(“ref = ” + cli.getRef());

}}

Page 157: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 25Vincenzo Gervasi

Parsare un URL

• Eseguendo l'esempio precedente si ottiene:

protocol = httpauthority = www.cli.di.unipi.it:80host = www.cli.di.unipi.itport = 80path = /faqquery = nullfilename = /faqref = null

Page 158: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 26Vincenzo Gervasi

Leggere da un URL

• Una volta creato un oggetto URL si può invocare il metodo openStream() per ottenere uno stream da cui poter leggere il contenuto dell’URL.

• Il metodo openStream() ritorna un oggetto java.io.InputStream leggere da un URL è analogo a leggere da uno stream di input.

import java.net.*;import java.io.*;public class URLReader {

public static void main(String[] args) throws Exception {URL cli = new URL(“http://www.cli.di.unipi.it/”);BufferedReader in = new BufferedReader(

new InputStreamReader(cli.openStream()));String inputLine;while ((inputLine = in.readLine()) != null)

System.out.println(inputLine);in.close();

}}

Page 159: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 27Vincenzo Gervasi

Leggere da un URL

• Una volta creato un oggetto URL si può invocare il metodo openStream() per ottenere uno stream da cui poter leggere il contenuto dell’URL.

• Il metodo openStream() ritorna un oggetto java.io.InputStream leggere da un URL è analogo a leggere da uno stream di input.

import java.net.*;import java.io.*;public class URLReader {

public static void main(String[] args) throws Exception {URL cli = new URL(“http://www.cli.di.unipi.it/”);BufferedReader in = new BufferedReader(

new InputStreamReader(cli.openStream()));String inputLine;while ((inputLine = in.readLine()) != null)

System.out.println(inputLine);in.close();

}}

args[0]

Page 160: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 28Vincenzo Gervasi

Leggere da un URL

• Eseguendo l'esempio precedente, si ottiene:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”“http://www.w3.org/TR/html4/loose.dtd”><html lang=”it”><head><meta http-equiv=”Content-Type” content=”text/html;charset=iso-8859-1”><link rel=”stylesheet” href=”/cdc.css” type=”text/css”><link rel=”alternate” type=”application/rss+xml”title=”Ultime notizie” href=”/feed.php”><title>Home CdC </title></head><body bgcolor=”#ced8e0”>....• Può essere necessario impostare il proxy su Java:java -Dhttp.proxyHost=proxyhost [-Dhttp.proxyPort=portNumber] URLReader

Page 161: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 29Vincenzo Gervasi

Connettersi a un URL• Nell’esempio precedente, la connessione all’URL veniva effettuata solo dopo

aver invocato openStream().

• In alternativa, è possibile invocare il metodo openConnection() per ottenere un oggetto URLConnection. Utile nel caso in cui si vogliano settare alcuni parametri o proprietà della

richiesta prima di connettersi. es: cliConn.setRequestProperty(“User-Agent”, “Mozilla/5.0”);

• Successivamente, si invoca URLConnection.connect().

URL cli = new URL(“http://www.cli.di.unipi.it/”);URLConnection cliConn = cli.openConnection();cliConn.connect();BufferedReader in = new BufferedReader(

new InputStreamReader(cliConn.getInputStream()));

Page 162: Java - Programmazione di Reti

ULezione 4: Indirizzi IP e URL 30Vincenzo Gervasi

URL e HTTPS• Tutto quanto detto vale anche per le connessioni sicure via HTTPS

import java.net.*;import java.io.*;

public class SecureClientUrl {public static void main(String[] args) {

try {URL url = new URL(“https://www.verisign.com”);URLConnection conn = url.openConnection();BufferedReader in = new BufferedReader(

new InputStreamReader(conn.getInputStream()));String inputLine;while ((inputLine = in.readLine()) != null)

System.out.println(inputLine);in.close();

} catch (Exception e){e.printStackTrace();}}

}

Page 163: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 1Andrea Corradini

Lezione n.6LPR-B-09

Il protocollo UDP:Socket e Datagram

27/10/2009Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 164: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 2Andrea Corradini

MECCANISMI DI COMUNICAZIONE TRA PROCESSI

Meccanismi di comunicazione tra processi (IPC)

Processo 2(Destinatario)

HOST 2HOST 1

Processo 1(Mittente)

HOST 1

Processo 1(Mittente)

HOST 1

Processo 1(Destinatario)

HOST n

Processo n(Destinatario)

dato

.

.

.

dato

dato

Page 165: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 3Andrea Corradini

COMUNICAZIONECONNECTION ORIENTED VS. CONNECTIONLESS

Comunicazione Connection Oriented (come una chiamata telefonica)• creazione di una connessione (canale di comunicazione dedicato)

tra mittente e destinatario• invio dei dati sulla connessione • chiusura della connessione

Comunicazione Connectionless (come l'invio di una lettera)● non si stabilisce un canale di comunicazione dedicato ● mittente e destinatario comunicano mediante lo scambio di pacchetti

Page 166: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 4Andrea Corradini

Indirizzamento: Connection Oriented: l’indirizzo del destinatario è specificato

al momento della connessione Connectionless: l’indirizzo del destinatario viene specificato in

ogni pacchetto (per ogni send)

• Ordinamento dei dati scambiati: Connection Oriented: ordinamento dei messaggi garantito Connectionless: nessuna garanzia sull’ordinamento dei messaggi

• Utilizzo: Connection Oriented: grossi streams di dati Connectionless : invio di un numero limitato di dati

COMUNICAZIONECONNECTION ORIENTED VS. CONNECTIONLESS

Page 167: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 5Andrea Corradini

COMUNICAZIONE:CONNECTION ORIENTED VS. CONNECTIONLESS

Protocollo UDP (User Datagram Protocol) =

connectionless, trasmette pacchetti di dati (Datagrams)

• ogni datagram deve contenere l’indirizzo del destinatario

• datagrams spediti dallo stesso processo possono seguire percorsi diversi ed arrivare al destinatario in ordine diverso rispetto all’ordine di spedizione

Protocollo TCP (Transmission Control Protocol) =

trasmissione connection-oriented o stream oriented• viene stabilita una connessione tra mittente e destinatario • su questa connesione si spedisce una sequenza di dati = stream di dati • per modellare questo tipo di comunicazione in JAVA si possono sfruttare i

diversi tipi di stream definiti dal linguaggio.

Page 168: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 6Andrea Corradini

IPC: MECCANISMI BASE

Una API per la comunicazione tra processi (IPC= Inter Process

Communication) deve garantire almeno le seguenti funzionalità

• Send per trasmettere un dato al processo destinatario

• Receive per ricevere un dato dal processo mittente

• Connect (solo per comunicazione connection oriented) per stabilire una connessione logica tra mittente e destinatario

• Disconnect per eliminare una connessione logica

Possono esistere diversi tipi di send/receive (sincrona/asincrona,

simmetrica/asimmetrica)

Page 169: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 7Andrea Corradini

IPC: MECCANISMI BASE

Un esempio: HTTP (1.0)

• il processo che esegue il Web browser esegue una connect per stabilire una connessione con il processo che esegue il Web Server

• il Web browser esegue una send, per trasmettere una richiesta al Web Server (operazione GET)

• il Web server esegue una receive per ricevere la richiesta dal Web Browser, quindi a sua volta esegue una send per inviare la risposta

• i due processi eseguono una disconnect per terminare la connessione

HTTP 1.1: Più richieste su una connessione (più send e receive).

Page 170: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 8Andrea Corradini

IPC: MECCANISMI BASE

Comunicazione sincrona (o bloccante): il processo che esegue la send o lareceive si sospende fino al momento in cui la comunicazione è completata.

send sincrona = completata quando i dati spediti sono stati ricevuti dal destinatario (è stato ricevuto un ack da parte del destinatario)

receive sincrona = completata quando i dati richiesti sono stati ricevuti

send asincrona (non bloccante) = il destinatario invia i dati e prosegue la sua esecuzione senza attendere un ack dal destinatario

receive asincrona = il destinatario non si blocca se i dati non sono arrivati. Possibile diverse implementazioni

Page 171: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 9Andrea Corradini

IPC: MECCANISMI BASE

•Receive Non Bloccante.

• se il dato richiesto è arrivato, viene reso disponibile al processo che ha eseguito la receive

• se il dato richiesto non è arrivato:

il destinatario esegue nuovamente la receive, dopo un certo intervallo di tempo (polling)

il supporto a tempo di esecuzione notifica al destinatario l’arrivo del dato (richiesta l’attivazione di un event listener)

Page 172: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 10Andrea Corradini

IPC: MECCANISMI BASE

• Comunicazione non bloccante: per non bloccarsi indefinitamente

Timeout – meccanismo che consente di bloccarsi per un intervallo di tempo prestabilito, poi di proseguire comunque l’esecuzione

Threads – l’operazione sincrona può essere effettuate in un thread. Se il thread si blocca su una send/receive sincrona, l’applicazione può eseguire altri thread.

Nel caso di receive sincrona, gli altri threads ovviamente non devono richiedere per l’esecuzione il valore restituito dalla receive

Page 173: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 11Andrea Corradini

INVIARE OGGETTI

Invio di strutture dati ed, in generale, di oggetti richiede :

• il mittente deve effettuare la serializzazione delle strutture dati (eliminazione dei puntatori)

• il destinatario deve ricostruire la struttura dati nella sua memoria

Da Wikipedia: La serializzazione è un processo per salvare un oggetto in un supporto di memorizzazione lineare (ad esempio, un file o un'area di memoria), o per trasmetterlo su una connessione di rete. La serializzazione può essere in forma binaria o può utilizzare codifiche testuali (ad esempio il formato XML)... Lo scopo della serializzazione è di trasmettere l'intero stato dell'oggetto in modo che esso possa essere successivamente ricreato nello stesso identico stato dal processo inverso, chiamato deserializzazione.

Il processo di serializzare un oggetto viene anche indicato come marshalling

Page 174: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 12Andrea Corradini

JAVA IPC: I SOCKETS

Socket = presa di corrente•Termine utilizzato in tempi remoti in telefonia. La connessione tra due utenti veniva stabilita tramite un operatore che inseriva fisicamente i due estremi di un cavo in due ricettacoli (sockets), ognuno dei quali era assegnato ai due utenti.

Socket è una astrazione che indica una “presa ” a cui un processo si può collegare per spedire dati sulla rete. Al momento della creazione un socket viene collegato ad una porta.

Socket

Page 175: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 13Andrea Corradini

Socket Application Program Interface = Definisce un insieme di meccanismiche supportano la comunicazione di processi in ambiente distribuito.

• JAVA socket API: definisce classi diverse per UDP e TCP

Protocollo UDP = DatagramSocket Protocollo TCP = ServerSocket e Socket

JAVA IPC: I SOCKETS

Page 176: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 14Andrea Corradini

FORMATO DEL PACCHETTO IP

IP VersionLungh.Header TOS Lungh. Datagram

Identific. Flag Offsetframmentazione

TTL Protocollo Checksum

Indirizzo Mittente

Indirizzo Destinatario

Opzioni

Dati

0

32

64

96

128

160

160/192+

Page 177: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 15Andrea Corradini

LIVELLO IP: FORMATO DEL PACCHETTOIP Version: IPV4 / IPV6

TOS (Type of Service) Consente un trattamento differenziato dei pacchetti.

Esempio: un particolare valore di TOS indica che il pacchetto ha una priorità

maggiore rispetto agli altri, Utile per distinguere tipi diversi di traffico

( traffico real time, messaggi per la gestione della rete,..)

TTL – Time to Live

Consente di limitare la diffusione del pacchetto sulla rete

• valore iniziale impostato dal mittente

• quando il pacchetto attraversa un router, il valore viene decrementato

• quando il valore diventa 0, il pacchetto viene scartato

Introdotto per evitare percorsi circolari infiniti del pacchetto. Utilizzato

anche per limitare la diffusione del pacchetto nel multicast

Page 178: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 16Andrea Corradini

LIVELLO IP: FORMATO DEL PACCHETTO

• Protocol: Il valore di questo campo indica il protocollo a livello

trasporto utilizzato (es: TCP 6, UDP 17, IPv6 41). Consente di

interpretare correttamente l'informazione contenuta nel datagram e

costituisce l'interfaccia tra livello IP e livello di trasporto

• Frammentazione: Campi utilizzati per gestire la frammentazione e la

successiva ricostruzione dei pacchetti

• Checksum: per controllare la correttezza del pacchetto

• Indirizzo mittente/destinatario

Page 179: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 17Andrea Corradini

L'HEADER UDP

• Datagram UDP = unità di trasmissione definita dal protocollo UDP

• Ogni datagram UDP

viene incapsulato in un singolo pacchetto IP

definisce un header che viene aggiunto all'header IP

Porta sorgente (0-65535) Porta Destinazione(0-65535)

Lunghezza Dati Checksum

DATI

0

32

64

Page 180: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 18Andrea Corradini

L'HEADER UDP

• L'header UDP viene inserito in testa al pacchetto IP

• contiene 4 campi, ognuno di 2 bytes

• i numeri di porta (0-65536) mittente/destinazione consentono un

servizio di multiplexing/demultiplexing

• Demultiplexing: l'host che riceve il pacchetto UDP decide in base al

numero di porta il servizio (processo) a cui devono essere consegnare i

dati

• Checksum: si riferisce alla verifica di correttezza delle 4 parole di 16

bits dell'header

• Lunghezza: lunghezza del datagram

Page 181: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 19Andrea Corradini

DATAGRAM UDP: LUNGHEZZE AMMISSIBILI

• IPV4 limita la lunghezza del datagram a 64K (65507 bytes + header)

• In pratica, la lunghezza del pacchetto UDP è limitata alla dimensione dei buffer associati al socket in ingresso/uscita dimensione del buffer = 8K nella maggior parte dei sistemi operativi. in certi sistemi si può incrementare la dimensione di questo buffer

• I routers IP possono frammentare i pacchetti IP che superano una certa dimensione se un pacchetto IP che contiene un datagram UDP viene frammentato,

il pacchetto non viene ricostruito e viene di fatto scartato per evitare problemi legati alla frammentazione, è meglio restringere

la lunghezza del pacchetto a 512 bytes

• E' possibile utilizzare dimension maggiori per pacchetti spediti su LAN

• IPV6 datagrams = 232 -1 bytes (jumbograms!)

Page 182: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 20Andrea Corradini

TRASMISSIONE PACCHETTI UDPPer scambiare un pacchetto UDP:

• mittente e destinatario devono creare due sockets attraverso i quali avviene la comunicazione.

• il mittente collega il suo socket ad una porta PM, il destinatario collega il suo socket ad una porta PD

Per spedire un pacchetto UDP, il mittente

• crea un socket SM collegato a PM

• crea un pacchetto DP (datagram).

• invia il pacchetto DP sul socket SMOgni pacchetto UDP spedito dal mittente deve contenere:

• indirizzo IP dell'host su cui è in esecuzione il destinatario + porta PD

• riferimento ad un vettore di bytes che contiene il valore del messaggio.

Page 183: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 21Andrea Corradini

TRASMISSIONE PACCHETTI UDP

Il destinatario, per ricevere un pacchetto UDP

• crea un socket SD collegato a PD

• crea una struttura adatta a memorizzare il pacchetto ricevuto

• riceve un pacchetto dal socket SD e lo memorizza in una struttura locale

i dati inviati mediante UDP devono essere rappresentati come vettori di bytes

JAVA offre diversi tipi di filtri per generare streams di bytes a partire da dati strutturati/ad alto livello

Page 184: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 22Andrea Corradini

TRASMISSIONE PACCHETTI UDP

Caratteristiche dei sockets UDP

• il destinatario deve “pubblicare” la porta a cui è collegato il socket di ricezione, affinchè il mittente possa spedire pacchetti su quella porta

• non è in genere necessario pubblicare la porta a cui è collegato il socket del mittente

• un processo può utilizzare lo stesso socket per spedire pacchetti verso destinatari diversi

• processi diversi possono spedire pacchetti sullo stesso socketallocato da un processo destinatario

socket

Page 185: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 23Andrea Corradini

JAVA : SOCKETS UDP

public class DatagramSocketCostruttori:public DatagramSocket( ) throws SocketException

• crea un socket e lo collega ad una porta anonima (o effimera), il sistema sceglie una porta non utilizzata e la assegna al socket. Per reperire la porta allocata utilizzare il metodo getLocalPort().

• utilizzato generalmente da un client UDP.

• Esempio: un client si connette ad un server mediante un socket collegato ad una porta anonima. Il server invia la risposta sullo stesso socket, prelevando l’indirizzo del mittente (IP+porta) dal pacchetto ricevuto. Quando il client termina, la porta viene utilizzata per altre connessioni.

Page 186: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 24Andrea Corradini

JAVA : SOCKETS UDP

Altro costruttore:

public DatagramSocket (int p ) throws SocketException

• crea un socket sulla porta specificata (p).

• viene sollevata un’eccezione (BindException / SocketException) se la porta è già utilizzata, oppure se si tenta di connettere il socket ad una porta su cui non si hanno diritti (SecurityException)

• utilizzato da un server UDP.

• Esempio: il server crea un socket collegato ad una porta resa nota ai clients. Di solito la porta viene allocata permanentemente a quel servizio (porta non effimera)

Page 187: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 25Andrea Corradini

INDIVIDUAZIONE DELLE PORTE LIBERE

Un programma per individuare le porte libere su un host:

import java.net.*;

public class ScannerPorte {

public static void main(String args[ ]){

for (int i = 1; i < 1024; i++){try {

new DatagramSocket(i);

System.out.println ("Porta libera"+i);

}

catch (BindException e) {System.out.println ("porta già in uso") ;}

catch (Exception e) {System.out.println (e);}

} }

Page 188: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 26Andrea Corradini

I DATAGRAMPACKET

• Un oggetto di tipo DatagramPacket può essere utilizzato per

memorizzare un datagram che deve essere spedito sulla rete

contenere i dati copiati da un datagram ricevuto dalla rete

• Struttura di un DatagramPacket

Buffer: riferimento ad un array di byte per la memorizzazione dei dati spediti/ricevuti

Metadati: • Lunghezza: quantità di dati presenti nel buffer• Offset: localizza il primo byte significativo nel buffer

InetAddress e porta del mittente o del destinatario

• I campi assumono diverso significato a seconda che il DatagramPacket

sia utilizzato per spedire o per ricevere dati

Page 189: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 27Andrea Corradini

LA CLASSE DATAGRAMPACKET

public final class DatagramPacket

public DatagramPacket (byte[ ] data, [int offset,] int length, InetAddress destination, int port)

• per la costruzione di un DatagramPacket da inviare sul socket

• length indica il numero di bytes che devono essere copiati dal vettore data[a partire dalla posizione offset] nel pacchetto UDP/IP.

• destination + port individuano il destinatario

• il messaggio deve essere trasformato in una sequenza di bytes e memorizzato nell'array data (strumenti necessari per la traduzione, es: metodo getBytes ( ), la classe java.io.ByteArrayOutputStream)

Page 190: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 28Andrea Corradini

LA CLASSE DATAGRAMPACKET

public DatagramPacket (byte[ ] data, [int offset,] int length)

• definisce la struttura utilizzata per memorizzare il pacchetto ricevuto..

• il buffer viene passato vuoto alla receive che lo riempie al momento della• ricezione di un pacchetto.

• il payload del pacchetto (la parte che contiene i dati) viene copiato nel buffer [a partire dalla posizione offset] al momento della ricezione.

• la copia del payload termina quando l'intero pacchetto è stato copiato oppure, se la lunghezza del pacchetto è maggiore di length, quando length bytes sono stati copiati

• il parametro length

prima della copia, indica il numero massimo di bytes che possono essere copiati nel buffer

dopo la copia, indica il numero di bytes effettivamente copiati.

Page 191: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 29Andrea Corradini

GENERAZIONE DEI PACCHETTI

Metodi per la conversione stringhe/vettori di bytes

• byte[ ] getBytes( ) applicato ad un oggetto String, restituisce una

sequenza di bytes che codifica i caratteri della stringa usando la

codifica di default dell'host

• String (byte[ ] bytes, int offset, int length) costruisce un nuovo

oggetto di tipo String decodificando la sottosequenza di length bytes

dall'array bytes, a partire dalla posizione offset

0 1 2 3 4 5 6 7 8 9 10 ...

offset 4 length 6

Page 192: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 30Andrea Corradini

INVIARE E RICEVERE PACCHETTI

Invio di pacchetti

• sock.send (dp)

dove: sock è il DatagramSocket attraverso il quale voglio spedire il pacchetto (DatagramPacket) dp

Ricezione di pacchetti• sock.receive(buffer)

dove sock è il DatagramSocket attraverso il quale ricevo il pacchetto e buffer è il DatagramPacket in cui memorizzo il pacchetto ricevuto

Page 193: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 31Andrea Corradini

COMUNICAZIONE TRAMITE SOCKETS: CARATTERISTICHE

• send non bloccante = il processo che esegue la send prosegue la sua esecuzione, senza attendere che il destinatario abbia ricevuto il pacchetto

• receive bloccante = il processo che esegue la receive si blocca fino al momento in cui viene ricevuto un pacchetto.per evitare attese indefinite è possibile associare al socket un timeout. Quando il timeout scade, viene sollevata una InterruptedIOException

ClientServer

receiverichiesta

risposta

send

receive

send

in esecuzione

bloccato

Page 194: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 32Andrea Corradini

RECEIVE CON TIMEOUT

• SO_TIMEOUT: proprietà associata al socket, indica l'intervallo di tempo, in

millisecondi, di attesa di ogni receive eseguita su quel socket

• Nel caso in cui l'intervallo di tempo scada, prima che venga ricevuto un

pacchetto dal socket, viene sollevata una eccezione di tipo

InterruptedIOException

• Metodi per la gestione di time out

public synchronized void setSoTimeout( int timeout) throws

SocketException

Esempio: se ds è un datagram socket, ds.setSoTimeout(30000)

associa un timeout di 30 secondi al socket ds.

Page 195: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 33Andrea Corradini

SEND/RECEIVE BUFFERS

• Ad ogni socket sono associati due buffers: uno per la ricezione ed uno per la spedizione

• Questi buffers sono gestiti dal sistema operativo, non dalla JVM. La loro dimensione dipende dalla piattaforma su cui il programma è in esecuzione

import java.net.*;

public class UDPBufferSize {public static void main (String args[]) throws Exception{

DatagramSocket dgs = new DatagramSocket();int r = dgs.getReceiveBufferSize(); int s = dgs.getSendBufferSize();System.out.println("receive buffer " + r);System.out.println("send buffer " + s); } }

• Stampa prodotta : receive buffer 8192 send buffer 8192 (8 Kbyte)

Page 196: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 34Andrea Corradini

SEND/RECEIVE BUFFERS • La dimensione del receive buffer deve essere almeno uguale a quella del

Datagram più grande che può essere ricevuto tramite quel buffer

• Receive Buffer: consente la bufferizzazione di un insieme di Datagram, nel caso in cui la frequenza con cui essi vengono ricevuti sia maggiore di quella con cui l'applicazione esegue la receive e quindi preleva i dati dal buffer

• La dimensione del send buffer viene utilizzata per stabilire la massima dimensione del Datagram

• Send Buffer: consente la bufferizzare di un insieme di Datagram, nel caso in cui la frequenza con cui essi vengono generati sia molto alta, rispetto alla frequenza con cui il supporto li preleva e spedisce sulla rete

• Per modificicare la dimensione del send/receive buffer

void setSendBufferSize(int size)

void setReceiveBufferSize(int size)

sono da considerare 'suggerimenti' al supporto sottostanta

Page 197: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 35Andrea Corradini

JAVA: IL CONCETTO DI STREAM

• Streams: introdotti per modellare l’interazione del programma con i dispositivi di I/O (console, files, connessioni di rete,…)

• JAVA Stream I/O: basato sul concetto di stream: si può immaginare uno stream come una condotta tra una sorgente ed una destinazione (dal programma ad un dispositivo o viceversa), da un estremo entrano dati, dall'altro escono

…..….. ReadWrite

• L’applicazione può inserire dati ad un capo dello stream

• I dati fluiscono verso la destinazione e possono essere estratti dall’altro capo dello stream Esempio: l'applicazione scrive su un FileOutputStream. Il dispositivo legge i dati e li memorizza sul file

Page 198: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 36Andrea Corradini

JAVA: IL CONCETTO DI STREAM

Caratteristiche principali degli streams:

• mantengono l’ordinamento FIFO

• read only o write only

• accesso sequenziale

• bloccanti: quando un’applicazione legge un dato dallo stream (o lo scrive) si blocca finchè l’operazione non è completata (ma le ultime versioni di JAVA introducono l’ I/O non bloccante: java.nio)

• non è richiesta una corrispondenza stretta tra letture/scritture

Esempio: una unica scrittura inietta 100 bytes sullo stream, che vengono letti con due read successive, la prima legge 20 bytes, la seconda 80 bytes

Page 199: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 37Andrea Corradini

STREAMS DI BASE: OUTPUTSTREAM

Streams di bytes: public abstract class OutputStream

Metodi di base:

public abstract void write (int b) throws IOException;

public void write(byte [ ] data) throws IOException;

public void write(byte [ ] data, int offset, int length) throws IOException;

La classe OutputStream ed il metodo write sono dichiarati astratti.

• write (int b) scrive su un OutputStream il byte meno significativo dell’intero passato (gli ultimi 8 bit dei 32)

• L’implementazione del metodo write può richiedere codice nativo (es: scrittura su un file…).

• Le sottoclassi descrivono stream legati a particolari dispositivi di I/O (file, console,…) .

Page 200: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 38Andrea Corradini

STREAMS DI BASE: INPUTSTREAM

Stream di bytes: public abstract class InputStream

Metodi di base:

public abstract int read () throws IOException;

public int read(byte [ ] b) throws IOException;

public int read(byte [ ] b, int offset, int length) throws IOException;

La classe InputStream ed il metodo read sono dichiarati astratti.

• read () restituisce un byte (un int nel rage 0-255) oppure -1 se ha raggiunto la fine dello stream.

• L’implementazione del metodo read può richiedere codice nativo (es: lettura da file…).

• Le sottoclassi descrivono input stream legati a particolari dispositivi di I/O (file, console,…) .

Page 201: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 39Andrea Corradini

STREAMS DI BASE E WRAPPERS

• Stream di base: classi utilizzate

*Stream utilizzate per la trasmissione di bytes

*Reader o *Writer: utilizzate per la trasmissione di caratteri

• Per non lavorare direttamente a livello di bytes o di carattere

Si definisce una serie di wrappers che consentono di avvolgere / incapsulare uno stream intorno all'altro ( come un tubo composto da più guaine...)

l'oggetto più interno è uno stream di base che 'avvolge' la sorgente dei dati (ad esempio il file, la connessione di rete,....).

i wrappers sono utilizzati per il trasferimento di oggetti complessi sullo stream, per la compressione di dati, per la definizione di strategie di buffering (per rendere più veloce la trasmissione)

Page 202: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 40Andrea Corradini

JAVA STREAMS: FILTRI

DataOutputStream consente di trasformare dati di un tipo primitivo JAVA in una sequenza di bytes da iniettare su uno stream.Alcuni metodi utili:

public final void writeBoolean(boolean b) throws IOException;

public final void writeInt (int i) throws IOException;

public final void writeDouble (double d) throws IOException;……

Il filtro produce una sequenza di bytes che rappresentano il valore del dato.Rappresentazioni utilizzate: • interi 32 bit complemento a due, big-endian • float 32 bit IEEE754 floating points Formati utilizzati dalla maggior parte dei protocolli di reteNessun problema se i dati vengono scambiati tra programmi JAVA.

Page 203: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 41Andrea Corradini

STREAMS DI BASE E WRAPPERS

InputStream, OuputStream consentono di manipolare dati a livello molto basso,per cui lavorare direttamente su questi streams risulta parecchio complesso.Per estendere le funzionalità degli streams di base: classi wrapper

applicazioneinteri

bytes

buffered bytes

file (data.txt)

DataOutputStream

BufferedOutputStream

FileOutputStream

DataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(“data.txt”)))

WRAPPER

Page 204: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 42Andrea Corradini

BYTEARRAY OUTPUT STREAMS

public ByteArrayOutputStream ( )public ByteArrayOutputStream (int size)• gli oggetti di questa classe rappresentano stream di bytes tali che ogni dato

scritto sullo stream viene riportato in un buffer di memoria (array di byte)a dimensione variabile (dimensione di default = 32 bytes).

• quando il buffer si riempie la sua dimensione viene raddoppiata • quindi consente di accedere ad un array di byte come se fosse uno stream;

l'array può essere estratto con il metodo toByteArray()

BUFFERByteArrayOutputStream

puntatore all’ultimo elemento inserito

Page 205: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 43Andrea Corradini

JAVA: USO DEGLI STREAM PER LA PROGRAMMAZIONE DI RETE

Come utilizzeremo gli streams in questo corso:

• Trasmissione connectionless:

ByteArrayOutputStream, consentono la conversione di uno stream di bytes in un array di bytes da spedire con i pacchetti UDP

ByteArrayInputStream, converte un array di bytes in uno stream di byte. Consente di manipolare più agevolmente i bytes

• Trasmissione connection oriented:

Una connessione viene modellata con uno stream.

invio di dati = scrittura sullo stream

ricezione di dati = lettura dallo stream

Page 206: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 44Andrea Corradini

BYTEARRAY OUTPUT STREAMS NELLA COSTRUZIONE DI PACCHETTI UDP

Ad un ByteArrayOutputStream può essere collegato un altro wrapper

ByteArrayOutputStream baos = new ByteArrayOutputStream( );

DataOutputStream dos = new DataOutputStream (baos)

Posso scrivere un dato di qualsiasi tipo sul DataOutputStream( )I dati presenti nel buffer B associato ad un ByteArrayOuputStream baospossono essere copiati in un array di bytes, di dimensione uguale alla dimensione attuale di B

byte [ ] barr = baos. toByteArray( )

datirete

DataOutputStream ByteArrayOutputStream

Buffer

ByteArray Pacchetto

Page 207: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 45Andrea Corradini

BYTEARRAY INPUT STREAMS

public ByteArrayInputStream ( byte [ ] buf )public ByteArrayInputStream ( byte [ ] buf, int offset, int length )

• creano stream di byte a partire dai dati contenuti nell'array di byte buf.

• il secondo costruttore copia length bytes iniziando alla posizione offset.

• E’ possibile incapsularlo in un DataInputStream

Ricezione di un pacchetto UDP dalla rete:

pacchetto Byte array

ByteArrayInputStream DataInputStream

Dati

Page 208: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 46Andrea Corradini

BYTE ARRAY INPUT/OUTPUT STREAMS

• Le classi ByteArrayInput/OutputStream facilitano l’invio dei dati di qualsiasi tipo (anche oggetti) sulla rete. La trasformazione in sequenza di bytes è automatica.

• uno stesso ByteArrayOuput/InputStream può essere usato per produrre streams di bytes a partire da dati di tipo diverso

• il buffer interno associato ad un ByteArrayOutputStream baos viene svuotato (puntatore all’ultimo elemento inserito = 0) con

• baos.reset ( )

• il metodo toByteArray non svuota il buffer!

Page 209: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 47Andrea Corradini

INVIO DI UDP DATAGRAMS

Ipotesi semplificativa: non consideriamo perdita/riordinamento di pacchetti

import java.io.*;

import java.net.*;

public class MultiDataStreamSender{

public static void main(String args[ ]) throws Exception{ // inizializzazione

InetAddress ia = InetAddress.getByName("localhost");

int port = 13350;

DatagramSocket ds = new DatagramSocket ( );

byte [ ] data = new byte [20];

DatagramPacket dp = new DatagramPacket(data, data.length, ia , port);

ByteArrayOutputStream bout= new ByteArrayOutputStream( );

DataOutputStream dout = new DataOutputStream (bout);

Page 210: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 48Andrea Corradini

for (int i=0; i< 10; i++){dout.writeInt(i); // scrivo 4 bytes nello streamdata = bout.toByteArray(); // estraggo l'array di bytedp.setData(data,0,data.length); // lo inserisco nel DatagramPacketdp.setLength(data.length); // definisco la lunghezza del bufferds.send(dp); // invio il DatagramPacket sul socketbout.reset( ); // svuoto lo streamdout.writeUTF("***"); // scrivo una stringa nello streamdata = bout.toByteArray( ); // ...dp.setData (data,0,data.length);

dp.setLength (data.length); ds.send (dp); bout.reset( ); } } }

INVIO DI UDP DATAGRAMS

Page 211: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 49Andrea Corradini

Ipotesi semplificativa: non consideriamo perdita/riordinamento di pacchettiimport java.io.*;import java.net.*;public class MultiDataStreamReceiver{

public static void main(String args[ ]) throws Exception{// fase di inizializzazioneFileOutputStream fw = new FileOutputStream("text.txt");DataOutputStream dr = new DataOutputStream(fw);int port = 13350;DatagramSocket ds = new DatagramSocket (port);byte [ ] buffer = new byte [200];DatagramPacket dp = new DatagramPacket (buffer, buffer.length);

RICEZIONE DI UDP DATAGRAMS

Page 212: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 50Andrea Corradini

for (int i = 0; i < 10; i++){

ds.receive(dp); // ricevo il DatagramPacket ByteArrayInputStream bin= // getLength() è il numero di byte letti

new ByteArrayInputStream(dp.getData(), 0, dp.getLength()); DataInputStream ddis= new DataInputStream(bin); int x = ddis.readInt(); // leggo un intero attraverso lo stream dr.writeInt(x); // lo scrivosul file System.out.println(x); // lo stampo ds.receive(dp); // ricevo altro DatagramPacket bin = new ByteArrayInputStream(dp.getData(), 0 ,dp.getLength()); ddis = new DataInputStream(bin); String y = ddis.readUTF( ); // leggo una stringa System.out.println(y); } } } // la stampo

RICEZIONE DI UDP DATAGRAMS

Page 213: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 51Andrea Corradini

Protocollo UDP: problemi

• Nel programma precedente, la corrispondenza tra la scrittura nel mittente e la lettura nel destinatario potrebbe non essere più corretta

• Esempio:

il mittente alterna la spedizione di pacchetti contenenti valori interi con pacchetti contenenti stringhe

il destinatario alterna la lettura di interi e di stringhe se un pacchetto viene perso ⇒ scritture/letture possono non

corrispondere

• Realizzazione di UDP affidabile: utilizzo di ack per confermare la ricezione + identificatori unici

Page 214: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 52Andrea Corradini

PER ESEGUIRE GLI ESERCIZI SU UN UNICO HOST

• Attivare il client ed il server in due diverse shell

• Se l’host è connesso in rete: utilizzare come indirizzo IP del mittente/destinatario l’indirizzo dell’host su cui sono in esecuzione i due processi (reperibile con InetAddress.getLocalHost( ) )

• Se l’host non è connesso in rete utilizzare l’indirizzo di loopback (“localhost” o 127.0.0.1)

• Tenere presente che mittente e destinatario sono in esecuzione sulla stessa macchina ⇒ devono utilizzare porte diverse

• Mandare in esecuzione per primo il server, poi il client

Page 215: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 53Andrea Corradini

ESERCIZIO 1: INVIO DI DATAGRAM UDP

Esercizio:

Scrivere un'applicazione composta da un processo Sender ed un processo Receiver. Il Receiver riceve da linea di comando la porta su cui deve porsi in attesa. Il Sender riceve da linea di comando una stringa e l’indirizzo del Receiver (indirizzo IP + porta), e invia al Receiver la stringa. Il Receiver riceve la stringa e stampa, nell'ordine, la stringa ricevuta, l'indirizzo IP e la porta del mittente.

Considerare poi i seguenti punti:

• cosa cambia se mando in esecuzione prima il Sender, poi il Receiver rispetto al caso in cui mando in esecuzione prima il Receiver?

• nel processo Receiver, aggiungere un time-out sulla receive, in modo che la receive non si bocchi per più di 5 secondi. Cosa accade se attivo il receiver, ma non il sender?

Page 216: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 54Andrea Corradini

ESERCIZIO 1: INVIO DI DATAGRAM UDP• Modificare il codice del Sender in modo che usi lo stesso socket per

inviare lo stesso messaggio a due diversi receivers. Mandare in esecuzione prima i due Receivers, poi il Sender. Controllare l'output dei Receiver.

• Modificare il codice del Sender in modo che esso usi due sockets diversi per inviare lo stesso messaggio a due diversi receivers. Mandare in esecuzione prima i due Receivers, poi il Sender.

• Modificare il codice ottenuto al passo precedente in modo che il Sender invii una sequenza di messaggi ai due Receivers. Ogni messaggio contiene il valore della sua posizione nella sequenza. Il Sender si sospende per 3 secondi tra un invio ed il successivo. Ogni receiver deve essere modificato in modo che esso esegua la receive in un ciclo infinito.

• Modificare il codice ottenuto al passo precedente in modo che il Sender non si sospenda tra un invio e l’altro. Cosa accade?

• Modificare il codice iniziale in modo che il Receiver invii al Sender un ack quando riceve il messaggio. Il Sender visualizza l’ack ricevuto.

Page 217: Java - Programmazione di Reti

ULezione 6: Il Protocollo UDP, sockets e datagrams 55Andrea Corradini

ESERCIZIO 2: COUNT DOWN SERVER

Si richiede di programmare un server CountDownServer che fornisceun semplice servizio: ricevuto da un client un valore intero n, il serverspedisce al client i valori n-1,n-2,n-3,….,1, in sequenza.La interazione tra i clients e CountDownServer è di tipo connectionless.Si richiede di implementare due versioni di CountDownServer realizzare CountDownServer come un server iterativo. L’applicazione riceve

la richiesta di un client, gli fornisce il servizio e solo quando ha terminato va a servire altre richieste

realizzare CountDownServer come un server concorrente. Si deve definire un thread che ascolta le richieste dei clients dalla porta UDP a cui è associato il servizio ed attiva un thread diverso per ogni richiesta ricevuta. Ogni thread si occupa di servire un client.

Opzionale: Il client calcola il numero di pacchetti persi e quello di quelli ricevuti fuori ordine e lo visualizza alla fine della sessione.Utilizzare le classi ByteArrayOutput/InputStream per la generazione/ricezione dei pacchetti.

Page 218: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 1Andrea Corradini

Lezione n.7LPR-B-08

UDP: Costruzione di pacchetti, e esercizi avanzati

10/11/2009Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 219: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 2Andrea Corradini

Invio di dati tramite UDP• codifica di dati primitivi come array di byte• invio di oggetti tramite serializzazione

Discussione di esercizi avanzati• MiniTalk (Instant Messanger)

– handshaking per stabilire una “connessione”– invio bidirezionale di stringhe

• TFTP (Trivial File Transfer Protocol)– protocollo per trasferimento di file in

lettura/scrittura tra client e server– simulazione di trasmissione basata su stream

SOMMARIO

Page 220: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 3Andrea Corradini

ABBIAMO VISTO CHE IN JAVA...

• Il protocollo UDP prevede la trasmissione di una sequenza (array) di bytes incapsulato in un DatagramPacket.

• Possiamo trasformare dati primitivi in sequenze di bytes da inserire all'interno del pacchetto usando

la classe DataOutputStream e i metodi writeInt(), writeDouble(), ...

la classe ByteArrayOutputStream e il metodo toByteArray()

• I dati possono essere ricostruiti dal mittente mediante

la classe ByteArrayInputStream

la classe DataInputStream e i metodi readInt(), readDouble(), ...

• Possiamo inviare più dati primitivi nello stesso pacchetto UDP, rileggendoli nello stesso ordine

Page 221: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 4Andrea Corradini

SENDER: INVIA PIU' DATI IN UN PACCHETTO

byte byteVal = 101;

short shortVal = 10001;

int intVal = 100000001;

long longVal = 100000000001L;

ByteArrayOutputStream buf = new ByteArrayOutputStream();

DataOutputStream out = new DataOutputStream(buf);

out.writeByte(byteVal);

out.writeShort(shortVal);

out.writeInt(intVal);

out.writeLong(longVal);

byte[ ] msg = buf.toByteArray( ); // Va inserito nel DatagramPacket // e spedito sul DatagramSocket

Page 222: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 5Andrea Corradini

RECEIVER: ESTRAE PIU' DATI DAL PACCHETTO...

ds.receive(dp); // si riceve il DatagramPacket

byte byteValIn;

short shortValIn;

int intValIn;

long longValIn;

ByteArrayInputStream bufin = new ByteArrayInputStream(dp.getData(), 0, dp.getLength());

DataInputStream in = new DataInputStream(bufin);

byteValIn = in.readByte();

shortValIn = in.readShort();

intValIn = in.readInt();

longValIn = in.readLong();

Page 223: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 6Andrea Corradini

CODIFICARE DATI PRIMITIVI COME BYTE[]• Il protocollo UDP (e come vedremo anche TCP) consente di inviare

unicamente sequenze di bytes. Un byte viene interpretato come un intero nell'intervallo [0..255].

• La codifica dei tipi di dato primitivi di un linguaggio in sequenze di bytes può essere realizzata

dal supporto del linguaggio (come visto nei lucidi precedenti)

più a basso livello, esplicitamente dal programmatore

• In ogni caso, il mittente ed il destinatario devono accordarsi sulla codifica stabilita. Ad esempio, per un dato di tipo intero si deve stabilire:

la dimensione in bytes per ogni tipo di dato

l'ordine dei bytes trasmessi,

l'interpretazione di ogni byte (con segno/senza segno)

• Il problema è semplificato se mittente e destinatario sono codificati mediante lo stesso linguaggio (ad esempio entrambi in JAVA)

Page 224: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 7Andrea Corradini

CODIFICARE VALORI DI TIPO PRIMITIVO

Per scambiare valori di tipo intero, occorre concordare:

dimensione dei tipi di dati scambiati: long: 8 bytes, int: 4 bytes, short: 2 bytes

ordine dei bytes trasmessi

Little-endian: il primo byte trasmesso è il meno significativo

Big-endian: il primo byte trasmesso è il più significativo

Interpretazione dei valori: con/senza segno

Nel caso di valori di tipo stringa, occorre concordare

codifica adottata per i caratteri contenuti nella stringa

UTF-8,

UTF-16

Page 225: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 8Andrea Corradini

CODIFICARE VALORI DI TIPO INTERO

• Supponiamo di dover costruire un pacchetto UDP contenente quattro valori interi: un byte, uno short, un intero ed un long

byte short int long

• Non si vogliono utilizzare le classi filtro DataOutputStrem e ByteArrayOutputStream

• Soluzione alternativa: si utilizzano operazioni che operano direttamente sulla rappresentazione degli interi

si definisce message, un vettore di bytes

si selezionano i bytes della rappresentazione mediante shifts a livello di bits

si inserisce ogni byte selezionato in una posizione del vettore message

Page 226: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 9Andrea Corradini

CODIFICARE VALORI DI TIPO INTERO

public static int encodePacket(byte[ ] dst, int offset, long val, int size){for (int i = size; i > 0; i--){

dst[offset++] = (byte) (val >> ((i - 1) * 8));}return offset;}

• val valore intero

• size dimensione, in bytes, del valore val

• i bytes che rappresentano val devono essere inseriti nel vettore dst, a partire dalla posizione offset

• si utilizza lo shift destro per selezionare i bytes, a partire dal più significativo

• il cast a byte del valore shiftato V restituisce gli 8 bits meno significativi di V, eliminando gli altri bits

Page 227: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 10Andrea Corradini

CODIFICARE VALORI DI TIPO INTEROpublic static void main(String args[ ])

{ byte byteVal=101, short shortVal = 8, int intVal = 53,

long longVal = 234567L;

final int BSIZE = 1;

final int SSIZE= Short.SIZE / Byte.SIZE;

final int ISIZE = Integer.SIZE/ Byte.SIZE;

final int LSIZE = Long.SIZE / Byte.SIZE;

byte [ ] message = new byte[BSIZE+SSIZE+ISIZE+LSIZE];

int offset = encodePacket(message,0, byteVal, 1);

offset = encodePacket(message,offset, shortVal, SSIZE);

offset = encodePacket(message,offset,intVal, ISIZE);

offset = encodePacket(message,offset, longVal, LSIZE);

............................

Page 228: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 11Andrea Corradini

DECODIFICARE VALORI DI TIPO INTEROpublic static long decodePacket(byte[ ] val, int offset, int size){

long rtn =0; int BYTEMASK = 0xFF;

for (int i= 0; i < size; i++){

rtn = (rtn << 8) | ((long) val[offset +i] & BYTEMASK); }

return rtn; }

• decodePacket: decodifica il valore di un dato reppresentato dai bytes contenuti nel vettore val, a partire dalla posizione offset. La dimensione (in byte) del valore da decodificare è size.

• Se si vuole 'riassemblare' il valore di tipo short dell'esempio precedente:short value = (short) decodePacket (message, BSIZE, SSIZE);

• “& BYTEMASK” è necessario per mettere a zero i bit più significativi (posizioni 0-55), che potrebbero essere ad 1 per il cast. Si provi il comando:

System.out.println((short) (byte) 128); // Stampa -128 ! Perché ?

Page 229: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 12Andrea Corradini

CODIFICA DI STRINGHE

• I caratteri vengono codificati in JAVA mediante Unicode che mappa i caratteri ad interi nell'intervallo [0..65535]

• Unicode è compatibile all'indietro con la codifica ASCII

• Il metodo getBytes( ) applicato ad una stringa restituisce un array di bytes contenente la rappresentazione della stringa, ottenuta secondo la codifica utilizzata di default dalla piattaforma su cui il programma viene eseguito

• E' possibile indicare esplicitamente la codifica desiderata, come argomento della getBytes()

• Esempio.

“Test!”.getBytes( )

“Test!”.getBytes(“UTF-16BE”)

• In generale mittente e destinatario devono accordarsi sulla codifica utilizzata per i valori di tipo stringa

Page 230: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 13Andrea Corradini

SERIALIZZAZIONE DI OGGETTI

• Le classi ObjectInputStream e ObjectOutputStream definiscono streams (basati su streams di byte) su cui si possono leggere e scrivere oggetti.

• La scrittura e la lettura di oggetti va sotto il nome di serializzazione, poiché si basa sulla possibilità di scrivere lo stato di un oggetto in una forma sequenziale, sufficiente per ricostruire l'oggetto quando viene riletto. La serializzazione di oggetti viene usata in diversi contesti:

Per inviare oggetti sulla rete, sia che si utilizzino i protocolli UDP o TCP, sia che si utilizzi RMI.

Per fornire un meccanismo di persistenza ai programmi, consentendo l'archiviazione di un oggetto per esempio in un file. Si pensi ad esempio ad un programma che realizza una rubrica telefonica o un'agenda.

Page 231: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 14Andrea Corradini

SERIALIZZAZIONE DI OGGETTI

Consente di convertire un oggetto E TUTTI QUELLO DA ESSO RAGGIUNGIBILI in una sequenza di bytes.

• Tale sequenza può essere utilizzata per ricostruire l’oggetto e il contesto.

• L’oggetto e tutti quelli raggiungibili devono essere definiti in classi che implementi l’interfaccia Serializable, che non ha metodi! Altrimenti viene lanciata una NotSerializableException.

• Tutte le classi involucro per i tipi di dati primitivi (es: Integer, Double, ...) e anche String implementano Serializable: quindi JAVA garantisce una serializzazione di default per tutti i dati primitivi.

• Per serializzare uno o più oggetti si utilizzano stream di tipo ObjectOutputStream e ObjectInputStream, e i rispettivi metodi writeObject() e readObject().

• Il meccanismo di serializzazione può essere personalizzato, ma non lo vediamo...

Page 232: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 15Andrea Corradini

LA CLASSE ObjectOutputStream

public ObjectOutputStream (OutputStream out) throws Exception

Quando si costruisce un oggetto di tipo ObjectOutputStream, viene automaticamente registrato in testa allo stream un header, costituito da due short, 4 bytes

(costanti MAGIC NUMBER + NUMERO DI VERSIONE)

• Magic Number = identifica univocamente un object stream

• I Magic Number vengono utilizzati in diversi contesti. Ad esempio, ogni struttura contenente la definizione di una classe Java deve iniziare con un numero particolare (magic number), codificato mediante una sequenza di 4 bytes, che identificano che quella struttura contiene effettivamente una classe JAVA [3405691582, 0xCAFEBABE]

• Se l’header viene cancellato lo stream risulta corrotto e l'oggetto non può essere ricostruito. Infatti al momento della ricostruzione dell'oggetto si controlla innanzi tutto che l'header non sia corrotto

Page 233: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 16Andrea Corradini

LA CLASSE ObjectInputStream

public ObjectInputStream (InputStream in) throws Exception

• L'header inserito dal costruttore di ObjectOutputStream viene letto e decodificato dal costruttore ObjectInputStream

• Se il costruttore ObjectInputStream( ) rileva qualche problema nel leggere l'header (ad esempio l'header è stato modificato o cancellato) viene segnalato che lo stream risulta corrotto

• L'eccezione sollevata è StreamCorruptedException

Page 234: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 17Andrea Corradini

TRASMISSIONE DI OGGETTI,SCHEMATICAMENTE

{oggetti}

ObjectOutputStream(ByteArrayOutputStream)

byte[ ]

DatagramPacket

writeObject( )

toByteArray()

DatagramPacket byte[ ]ObjectInputStream(ByteArrayInputStream)

readObject( )

{oggetti}

DatagramSocket

DatagramSocket

send( )

receive( )

UDP/IP on Internet

Page 235: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 18Andrea Corradini

UN ESEMPIO DI TRASMISSIONE DI OGGETTI

import java.io.*; import java.net.*; import java.util.Vector;public class UDP_SendObject {

public static void main(String[] args) throws IOException {// build interesting objectVector<Object> vett = new Vector<Object>();vett.add(new Integer(74));vett.add("Questa e' una stringa");vett.add(new java.awt.Rectangle(3,4,10,20));// prepare data to be sent using object streamByteArrayOutputStream bout = new ByteArrayOutputStream();ObjectOutputStream oout = new ObjectOutputStream(bout);oout.writeObject(vett);byte[] arr = bout.toByteArray();

Page 236: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 19Andrea Corradini

UN ESEMPIO DI TRASMISSIONE DI OGGETTI

// continua la classe UDP_SendObject // prepare Datagram socket and packetDatagramSocket ds = new DatagramSocket();InetAddress ia = InetAddress.getByName("localhost");int port = 24309;DatagramPacket dp = new DatagramPacket(arr,arr.length,ia,port);// sendds.send(dp);

}}

Page 237: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 20Andrea Corradini

UN ESEMPIO DI TRASMISSIONE DI OGGETTI

import java.io.*; import java.net.*; import java.util.Vector;public class UDP_ReceiveObject {

public static void main(String[] args) throws IOException,SocketException,ClassNotFoundException{DatagramSocket ds = new DatagramSocket(24309);DatagramPacket dp = new DatagramPacket(new byte[512],512);ds.receive(dp); // receive packetByteArrayInputStream bais =

new ByteArrayInputStream(dp.getData(),dp.getOffset(),dp.getLength());ObjectInputStream ois = new ObjectInputStream(bais);Vector<Object> vett = (Vector<Object>) ois.readObject();for (Object o : vett){ System.out.println(o.getClass() + ": " + o); } } }

Page 238: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 21Andrea Corradini

UN ESEMPIO DI TRASMISSIONE DI OGGETTI

L'output del programma mostra che il vettore e il suo contenuto sono arrivati correttamente al receiver:

class java.lang.Integer: 74

class java.lang.String: Questa e' una stringa

class java.awt.Rectangle: java.awt.Rectangle[x=3,y=4,width=10,height=20]

Page 239: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 22Andrea Corradini

ATTENZIONE: UN ObjectOutputStream PER PACCHETTO!

public class Test {

public static void main(String args[ ]) throws Exception{ByteArrayOutputStream bout = new ByteArrayOutputStream ( );System.out.println (bout.size( )); // Stampa 0ObjectOutputStream out= new ObjectOutputStream(bout);System.out.println (bout.size( )); // Stampa 4: l'header è creatoout.writeObject("prova");System.out.println (bout.size( )); //Stampa 12// Spedisco il contenutobout.reset ( ); //Necessario per eliminare bytes già speditiout.writeObject("prato");System.out.println (bout.size( )); //Stampa 8 = 12-4. }}

• la reset() ha distrutto l’header dello stream!!!

Page 240: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 23Andrea Corradini

ESERCIZIO 1: UNA CLASSE AUSILIARIA PERTRASMETTERE OGGETTI

Scrivere la classe Obj2DP che fornisce due metodi statici: public static Object dp2obj(DatagramPacket dp)

che restituisce l'oggetto contenuto nel pacchetto passato per argomento, deserializzandolo

public static DatagramPacket obj2dp(Object obj)

che restituisce un pacchetto contenente l'oggetto passato per argomento, serializzato, nel payload.

• Semplificare le classi UDP_SendObject e UDP_ReceiveObject viste prima usando i metodi della classe Obj2DP, senza più usare le classi ObjectOutput/InputStream e ByteOutput/InputStream.

• Usare la classe Obj2DP per i prossimi esercizi, trasmettendo oggetti serializzati con UDP invece di dati di tipi primitivi.

Page 241: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 24Andrea Corradini

ESERCIZIO 2: MiniTalk Server e Client con UDP (1)

Si realizzino un Server e un Client UDP che realizzano un semplice Instant Messanger: ogni linea scritta nella shell del Server viene copiata nella shell del Client e viceversa. La trasmissione delle linee inizia dopo una semplice fase di handshaking, descritta di seguito.

Il Server viene lanciato da shell, fornendo il numero di porta su cui ricevere i pacchetti UDP.

Il Client viene lanciato da un'altra shell (eventualmente su un altro computer), fornendo host e porta del Server e porta locale su cui ricevere pacchetti UDP.

Il Client manda una richiesta di connessione al Server, indicando nel messaggio la propria porta. Se non riceve un messaggio di ack entro 3 secondi, riprova a mandare la richiesta altre 5 volte, poi termina. Se invece riceve l'ack, inizia la trasmissione delle linee scritte nella shell locale e la ricezione e stampa delle linee scritte nella shell del Server.

Page 242: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 25Andrea Corradini

ESERCIZIO 2: MiniTalk Server e Client con UDP (2)

Quando il Server riceve una richiesta di connessione, recupera indirizzo e porta del Client dalla richiesta e manda un messaggio di ack al Client, quindi comincia la trasmissione e ricezione delle stringhe come descritto per il Client.

Il Client decide quando disconnettersi in base a una condizione a vostra scelta (per esempio, allo scadere di un timeout, oppure se la linea da mandare è vuota, oppure se la stringa è “CLOSE”,...).

Per disconnettersi, il Client manda una richiesta di disconnessione al Server e aspetta un ack, quindi termina l'esecuzione.

Quando il Server riceve una richiesta di disconnessione interrome la trasmissione delle linee, manda un messaggio di ack, e si rimette in attesa di una richiesta di connessione.

Il Client e il Server devono scambiarsi unicamente oggetti della classe TalkMsg, usando i metodi della classe per crearne istanze e per ispezionare i messaggi arrivati.

Page 243: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 26Andrea Corradini

ESERCIZIO 3: MiniTalk Messanger con UDP

Riusando il più possibile il codice sviluppato per l'esercizio precedente, realizzare un programma Messanger che offre le stesse funzionalità, ma in cui non si distinguono un Server e un Client.

Due istanze di Messanger devono essere lanciate in due shell diverse, fornendo ad ognuna tre dati: la porta locale, e l'host e la porta dell'altro Messanger. Ideare un opportuno protocollo di handshaking, che permetta di stabilire una connessione (concettuale) tra le due istanze di Messanger.

I messaggi scambiati devono essere tutti oggetti di una stessa classe. Usare la classe TalkMsg, oppure estenderla o definirne una analoga se necessario.

Page 244: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 27Andrea Corradini

ESERCIZIO 4: TFTP con UDP(Trivial File Transfer Protocol) [1]

Questa è la specifica di TFTP da WIKIPEDIA:

• L'host A invia un pacchetto RRQ (read request) o WRQ (write request) all'host B, contenente il nome del file e la modalità di trasferimento.

• B risponde con un ACK (acknowledgement) packet, che serve anche a dire ad A quale porta sull'host B dovrà usare per i restanti pacchetti.

• L'host di origine invia dei pacchetti DATA numerati all'host di destinazione, tutti tranne l'ultimo contenenti un blocco di dati completo. L'host di destinazione risponde con un pacchetto ACK numerato per ogni pacchetto DATA.

• Il pacchetto DATA finale deve contenere un blocco di dati non pieno ad indicare che si tratta dell'ultimo. Se la dimensione del file trasferito è un multiplo esatto della dimensione dei blocchi, la sorgente invia un ultimo pacchetto di dati contente 0 byte di dati.

Page 245: Java - Programmazione di Reti

Lezione 7: Il Protocollo UDP: costruzione pacchetti ed esercizi 28Andrea Corradini

ESERCIZIO 4: TFTP con UDP(Trivial File Transfer Protocol) [2]

Realizzare un Server TFTP che implementa il comportamento dell'host B e un Client TFTP che implementa l'host A. In particolare:

• Client e Server devono scambiarsi solo oggetti di una classe, TFTPmsg, usati sia per messaggi di servizio (RRQ, WRQ, ACK) che per i pacchetti DATA: definire opportunamente la classe TFTPmsg.

• Per il trasferimento dei file, considerarli come file binari, usando quindi opportuni Output/InputStreams (e non Writer/Reader).

• Inviare le porzioni di file in array di byte all'interno di un'istanza di TFTPmsg.

Per testare il programma:

• Confrontare il file originale spedito dal mittente con quello ricevuto dal destinatario e scritto nel file system.

• Usare la classe UnreliableDatagramSocket per controllare che i pacchetti persi vengano reinviati correttamente.

Page 246: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 1Andrea Corradini

Lezione n.7LPR-B-09

TCP: Stream Sockets 17/11/2009

Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 247: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 2Andrea Corradini

DATAGRAM SOCKET API:RIASSUNTO DELLE PUNTATE PRECEDENTI

• lo stesso Datagram Socket può essere utilizzato per spedire messaggi verso destinatari diversi

• processi diversi possono inviare datagrams sullo stesso socket di un processo destinatario

• send non bloccante:se il destinatario non è in esecuzione quando il mittente esegue la send, il messaggio può venir scartato

• receive bloccante:uso di timeouts associati al socket per non bloccarsi indefinitamente sulla receive

• i messaggi ricevuti vengono troncati se la dimensione del buffer del destinatario è inferiore a quella del messaggio spedito (provatelo!)

Page 248: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 3Andrea Corradini

DATAGRAM SOCKET API:RIASSUNTO DELLE PUNTATE PRECEDENTI

• protocollo UDP (User Datagram Protocol) non implementa controllo del flusso: se la frequenza con cui il mittente invia i messaggi è sensibilmente maggiore di quella con cui il destinatario li riceve (li preleva dal buffer di ricezione) è possibile che alcuni messaggi sovrascrivano messaggi inviati in precedenza

• Esempio: CountDown Server (vedi prima esercitazione su UDP). Il client invia al server un valore di n “grande” (provare valori>1000). Allora: il server deve inviare al client un numero molto alto di pacchetti il tempo che intercorre tra l’invio di un pacchetto e quello del pacchetto

successivo è basso dopo un certo numero di invii il buffer del client si riempie ⇒ perdita di

pacchetti

Page 249: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 4Andrea Corradini

COUNT DOWN SERVER UDP

n

.

n,n-1,n-2,...

• Si può utilizzare lo stesso socket per inviare n e per ricevere i risultati

• Quando il CountDownClient invia il valore n il CountDownServer deve aver allocato il socket, altrimenti il pacchetto viene perduto

CountDownClient CountDownServer

Page 250: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 5Andrea Corradini

COUNT DOWN SERVER UDP

n

.n,n-1,n-2,...

● Posso utilizzare sockets diversi per la spedizione/ricezione ● In questo caso può accadere che sock2 non sia ancora stato creato

quando CountDownServer inizia ad iniziare la sequenza di numeri ● E' possibile che il CountDownClient si blocchi sulla receive poiché i dati

inviati dal CountDownServer sono stati inviati prima della creazione del socket e quindi sono andati persi

CountDownClient CountDownServer

sock1

sock2

Page 251: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 6Andrea Corradini

IL PROTOCOLLO TCP: STREAM SOCKETS

• Il protocollo TCP (Transmission Control Protocol) supporta un modello computazionale di tipo client/server, in cui il server riceve

dai clients richieste di connessione, le schedula e crea connessioni diverse per ogni richiesta ricevuta

ogni connessione supporta comunicazioni bidirezionali, affidabili

• La comunicazione connection-oriented prevede due fasi: il client richiede una connessione al server quando il server accetta la connessione, client e server iniziano a

scambiarsi i dati

• In JAVA, ogni connessione viene modellata come uno stream di bytes i dati non vengono incapsulati in messaggi (pacchetti) stream sockets: al socket sono associati stream di input/output usa il modello di I/O basato su streams definito in UNIX e JAVA

Page 252: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 7Andrea Corradini

IL PROTOCOLLO TCP: STREAM SOCKETS

• Esistono due tipi di socket TCP: Listening (o passive) sockets: utilizzati dal server per accettare le

richieste di connessione Active Sockets: supportano lo streaming di byte tra client e server

• Il server utilizza un listening socket per accettare le richieste di connessione dei clients

• Il client crea un active socket per richiedere la connessione

• Quando il server accetta una richiesta di connessione, crea a sua volta un proprio active socket che rappresenta il punto

terminale della sua connessione con il client la comunicazione vera e propria avviene mediante la coppia di active

sockets presenti nel client e nel server

Page 253: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 8Andrea Corradini

IL PROTOCOLLO TCP: STREAM SOCKETS

Listening Socket

SIP = Indirizzo IP del ServerClient1

Client2

PL=Porta Locale

PL=Porta Locale

PR = Porta Remota

Active Socket

Active Socket

Richiesta di apertura di connessione. Il client • crea un active socket S e lo associa alla sua porta locale PL • collega S al listening socket presente sul server pubblicato all'indirizzo (SIP, PR)

Page 254: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 9Andrea Corradini

IL PROTOCOLLO TCP: STREAM SOCKETS

Listening Socket

Client1

Client2

PL=Porta Locale

PL=Porta Locale

PR = Porta Remota

Active Socket

Active Socket

Apertura di una connessione* il server accetta la richiesta di connessione e crea un proprio active socket che rappresenta il suo punto terminale della connessione* tutti i segmenti TCP scambiati tra client e server vengono trasmessi mediante la coppia di active sockets creati

Active Socket

Active Socket

SIP = Indirizzo IP del Server

Page 255: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 10Andrea Corradini

Apertura di una connessioneThree ways handshake

• 1) Il client A invia un segmento SYN a B - il flag SYN vale 1 e il campo Sequence number contiene il valore x che specifica l'Initial Sequence Number (ISN) di A;

• 2) B invia un segmento SYN/ACK ad A - i flag SYN e ACK sono impostati a 1, il campo Sequence number contiene il valore y che specifica l'ISN di B e il campo Acknowledgment number contiene il valore x+1 confermando la ricezione del ISN di A;

• 3) A invia un segmento ACK a B - il campo Acknowledgment number contiene il valore y+1 confermando la ricezione del ISN di B.

• Il terzo segmento permette anche all'host B una stima del timeout iniziale, come tempo intercorso tra l'invio di un segmento e la ricezione del corrispondente ACK.

Page 256: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 11Andrea Corradini

Page 257: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 12Andrea Corradini

IL PROTOCOLLO TCP: STREAM SOCKETS

Il server pubblica un proprio servizio associandolo al listening socket, creato sulla porta remota PR Il client C che intende usufruire del servizio deve conoscere l'indirizzo IP del server, SIP ed il riferimento alla porta remota PR a cui è associato il servizio La richiesta di creazione del socket

produce in modo atomico la richiesta di connessione al server il protocollo di richiesta della connessione viene completamente gestito dal

supporto Quando la richiesta di connessione viene accettata dal server, il supporto in esecuzione sul server crea in modo automatico un nuovo active socket AS.

AS è utilizzato per l’interazione con il client. Tutti i messaggi spediti dal client vengono diretti automaticamente sul nuovo socket creato.

Page 258: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 13Andrea Corradini

STREAM SOCKET JAVA API: LATO CLIENTClasse java.net.Socket : costruttori

public Socket(InetAddress host, int port) throws IOException– crea un active socket e tenta di stabilire, tramite esso, una

connessione con l’host individuato da InetAddress, sulla porta port. Se la connessione viene rifiutata, lancia una eccezione di IO

public Socket (String host, int port) throws UnKnownHostException, IOE...– come il precedente, l’host è individuato dal suo nome simbolico

(interroga automaticamente il DNS)

public Socket (String host, int port, InetAddress locIA, int locPort) ....– tenta di creare una connessione verso l’host host, sulla porta port,

dalla interfaccia locale localIA, dalla porta locale locPort– utile per macchine dotate di più schede di rete, ad esempio un host con

due indirizzi IP, uno visibile da Internet, l’altro solo a livello di rete locale.

Page 259: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 14Andrea Corradini

PORT SCANNER: INDIVIDUAZIONE SERVIZI TCP ATTIVI SU UN HOST

import java.net.*; import java.io.*;

public class TCPPortScanner {

public static void main(String args[ ]){

String host;

try { host = args[0];

} catch (ArrayIndexOutOfBoundsException e) { host= "localhost"; };

for (int i = 1; i< 1024; i++){try{ new Socket(host, i);

System.out.println("Esiste un servizio sulla porta" + i); } catch (UnknownHostException ex){

System.out.println("Host Sconosciuto"); } catch (IOException ex) {

System.out.println("Non esiste un servizio sulla porta"+i); }}}}

Page 260: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 15Andrea Corradini

PORT SCANNER: INDIVIDUAZIONE SERVIZI TCP ATTIVI SU UN HOST

• Nella classe TCPPortScanner– il client richiede la connessione tentando di creare un socket su ognuna

delle prime 1024 porte di un host– nel caso in cui non vi sia alcun servizio attivo, il socket non viene creato

e viene invece sollevata un'eccezione– Osservazione: il programma effettua 1024 interrogazioni al DNS, una

per ogni socket che tenta di creare• Per migliorare il comportamento del programma: utilizzare il costruttore

public Socket(InetAddress host, int port) throws IOException

– il DNS viene interrogato una sola volta, prima di entrare nel ciclo di scanning, dalla InetAddress.getByName

– si usa l’InetAddress invece del nome dell’host per costruire i sockets

Page 261: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 16Andrea Corradini

STREAM BASED COMMUNICATION

Dopo che la richiesta di connessione viene accettata, client e server

● associano agli active socket streams di byte di input/output

● poichè gli stream sono unidirezionali si usano due stream diversi, associati agli stessi socket, rispettivamente per l'input e per l'output

● la comunicazione avviene mediante lettura/scrittura di dati sullo stream

● come sempre, si possono usare wrappers con gli stream

Descriptor: Local port, Local IPaddr, Remote Port, Remote IPaddr

OutputStream

InputStream

Send Buffer

Receive Buffer

Struttura del Socket TCP

Page 262: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 17Andrea Corradini

NETSTAT: ANALIZZARE LO STATO DI UN SOCKET

Uno 'snapshot' dei socket a cui sono state associate connessioni attive può essere ottenuto mediante l'utility netstat (network statistics), disponibile sui principali sistemi operativi

Page 263: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 18Andrea Corradini

NETSTAT: ANALIZZARE LO STATO DI UN SOCKET

• Proto: protocollo associato al socket (TCP, UDP,...)

• RecV-Q, Send-Q: numero di bytes presenti nel receive buffer e nel send buffer

• Local Address: indirizzo IP + porta locale a cui è associato il socket

• Foreign Address: indirizzo IP + porta a cui è associato il socket

• State: stato della connessione– LISTEN : il server sta attendendo richieste di connessione– TIMEWAIT: il client ha iniziato la procedura di chiusura della

connessione, che non è ancora stata completata– ESTABLISHED: Il client ha ricevuto il SYN dal server (3-way

handshake completato) e la connessione è stata stabilita– Altri stati corrispondono ai diversi stati del 3-way handshake o del

protocollo definito da TCP per la chiusura del socket

Page 264: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 19Andrea Corradini

STREAM BASED COMMUNICATIONPer associare uno stream di input/output ad un socket esistono i metodi

public InputStream getInputStream( ) throws IOException

public OutputStream getOutputStream( ) throws IOException

che applicati ad un oggetto di tipo Socket restituiscono uno stream associato al socket ogni valore scritto su uno stream di output associato al socket viene

copiato nel Send Buffer ogni valore letto dallo stream viene prelevato dal Receive Buffer

Il client può leggere dallo stream

• un byte/ una sequenza di bytes

• dati di tipo qualsiasi (anche oggetti) mediante l’uso di opportuni filtri (DataInputStream, ObjectInputStream,… )

Page 265: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 20Andrea Corradini

UN SEMPLICE ESEMPIO DI CLIENT TCP: ECHO

import java.net.*; import java.io.*; import java.util.*;

public class TCPEchoClient {

public static void main (String args[]) throws Exception{

Scanner console = new Scanner( System.in); // per leggere da tastiera

InetAddress ia = InetAddress.getByName("localhost");

int port = 12345; Socket echosocket = null;

try{ echosocket = new Socket (ia, port);} //creo socket e connessione

catch (Exception e){System.out.println(e); return;}

InputStream is = echosocket.getInputStream( ); // creo input stream

DataInputStream netIn = new DataInputStream(is);

OutputStream os = echosocket.getOutputStream( ); //creo output str-

DataOutputStream netOut = new DataOutputStream(os);

Page 266: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 21Andrea Corradini

boolean done=false;

while (! done){

String linea = console.nextLine( ); // leggo da tastiera

System.out.println (linea);

netOut.writeUTF(linea); // scrivo sull'output stream del socket

NetworkOut.flush( );

String echo = netIn.readUTF( ); // leggo dall'input stream

System.out.println (“> “ + echo);

if (linea.equals("exit")) {done = true;

echosocket.close ( ); } // chiudo il socket

} } } }

UN SEMPLICE ESEMPIO DI CLIENT TCP: ECHO

Page 267: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 22Andrea Corradini

STRUTTURA DI UN SERVER

Comportamento di un Server Sequenziale:

• crea un Listening Socket LS sulla porta associata al servizio pubblicato.

• si mette in ascolto su LS (si blocca fino al momento in cui arriva una richiesta di connessione)

• quando accetta una richiesta di connessione da parte di un client C, crea un nuovo Active Socket su cui avviene la comunicazione con C

• associa all' Active Socket uno o più stream (di input e/o di output) su cui avverrà la comunicazione con il client

• quando l’interazione con il client è terminata, chiude il data socket e torna ad ascoltare su LS ulteriori richieste di connessione

Page 268: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 23Andrea Corradini

STREAM MODE SOCKET API: LATO SERVER

Classe java.net.ServerSocket: costruttori

public ServerSocket(int port) throws BindException, IOException

public ServerSocket(int port, int length) throws BindException, IOException– costruisce un listening socket, associandolo alla porta port. Il

parametro length indica la lunghezza della coda in cui vengono memorizzate le richieste di connessione (lunghezza massima della coda stabilita dal sistema operativo). Se la coda è piena, eventuali ulteriori richieste di connessione vengono rifiutate.

public ServerSocket(int port, int length, InetAddress bindAddress) throws...– permette di collegare il socket ad uno specifico indirizzo IP locale. – utile per macchine dotate di più schede di rete, ad esempio un host con

due indirizzi IP, uno visibile da Internet, l’altro solo a livello di rete locale.

Page 269: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 24Andrea Corradini

Esempio: ricerca dei servers attivi sull’host locale, catturando le BindException

import java.net.*;

public class TCPLocalServerScanner {

public static void main(String args[]){

for (int port= 1; port<= 1024; port++)

try {new ServerSocket(port);}

catch (BindException ex) {System.out.println(port + "occupata");}

catch (Exception ex) {System.out.println(ex);}

}

}

STREAM MODE SOCKET API: LATO SERVER

Page 270: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 25Andrea Corradini

Per accettare una nuova connessione dal listening socket si usa il metodo:

public Socket accept( ) throws IOException

della classe ServerSocket che restituisce l'active socket per la connessione.

• quando il processo server invoca il metodo accept( ), pone il server in attesa di nuove connessioni.

• se non ci sono richieste, il server si blocca (possibile utilizzo di time-outs)

• se c’è almeno una richiesta, il processo si sblocca e costruisce un nuovo socket tramite cui avviene la comunicazione effettiva tra cliente server

STREAM MODE SOCKET API: LATO SERVER

Page 271: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 26Andrea Corradini

ESEMPIO DI SERVER TCP: ECHO

Echo Server

• si mette in attesa di richieste di connessione

• dopo aver accettato una connessione, si mette in attesa di una stringa dal client e gliela rispedisce

• quando riceve la stringa “exit” chiude la connessione con quel client e torna ad accettare nuove connessioni

Page 272: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 27Andrea Corradini

import java.net.*; import java.io.*;

public class TCPEchoServer {

public static void main(String args[]) throws Exception{

int port= 12345;

ServerSocket ss = new ServerSocket(port,2); // listener socket

while (true){Socket sdati = ss.accept( ); // accetto e creo active socketInputStream is = sdati.getInputStream( ); // creo input streamDataInputStream netIn = new DataInputStream(is);OutputStream out = sdati.getOutputStream( ); // creo output strDataOutputStream netOut = new DataOutputStream(out);

ESEMPIO DI SERVER TCP: ECHO

Page 273: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 28Andrea Corradini

boolean done = false;while (!done){ // ciclo ascolta/ripeti

String echo = netIn.readUTF( );netOut.writeUTF(echo);

if (echo.equals("exit")){ // termine servizio System.out.println("finito"); done = true;} // interrompe ciclo e si rimette in ascolto

} } } }

ESEMPIO DI SERVER TCP: ECHO

Page 274: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 29Andrea Corradini

TCP BUFFERING

Per analizzare il comportamento dei buffer associati ad un socket TCP, consideriamo prima il caso in cui l'applicazione legga/scriva direttamente sequenze di bytes (contenute in array di bytes gestiti dall'applicazione) sugli/dagli stream.

byte [ ]

Send-Q Recv-Q

Gestito dal Supporto

Gestito dalla

applicazione

Gestito dal

Supporto

Gestito dalla

applicazione

byte [ ]

Page 275: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 30Andrea Corradini

TCP BUFFERING• Ipotesi: si utilizzano write/read, per scrivere/leggere array di byte

sugli/dagli streams.– La write( ) trasferisce i byte nel Send-Q buffer, se esiste abbastanza

spazio nel buffer. Se non riesce a scrivere tutti i byte nel Send-Q buffer, si blocca.

– La read( ) legge i dati disponibili nel Recv-Q al momento della invocazione sull'InputStream. Se Recv-Q buffer non contiene dati si blocca.

• Non esiste, in generale, alcuna corrispondenza tra

– le scritture effettuate sull'OutputStream ad un capo dello stream, e

– le letture dall'InputStream effettuate all'altro capo

• I dati scritti sull'OutputStream mediante una singola scrittura possono, in generale, essere letti mediante un insieme di operazioni di lettura

Page 276: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 31Andrea Corradini

TCP BUFFERING: UN ESEMPIO

byte [ ] buffer0 = new byte[1000];

byte [ ] buffer1 = new byte[2000];

byte [ ] buffer2 = new byte[5000];

....

Socket s = new Socket(destAddr, destPort); // creo active socket

OutputStream out = s.getOutputStream( ); // creo output stream

.....

out.write(buffer0); .... // scrivo 1000 bytes

out.write(buffer1); .... // scrivo 2000 bytes

out.write(buffer2); .... // scrivo 5000 bytes

s.close();

Page 277: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 32Andrea Corradini

TCP BUFFERING: STATO DEI BUFFERS

Stato dei buffer dopo l'esecuzione di tutte le write( ), ma prima di una qualsiasi operazione di read, uno scenario possibile

Questo scenario può essere analizzato mediante l'esecuzione di netstat

Mittente

Destinatario

Page 278: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 33Andrea Corradini

TCP BUFFERING: STATO DEI BUFFERS

• Se il ricevente esegue una read con un byte array di dimensione 2000, nella situazione mostrata dalla figura precedente, la read

– riempe parzialmente il byte array

– l'applicazione riceve 1000 byte prodotti dalla prima write( ) e 500 dalla seconda

• Se necessario, l'applicazione deve utilizzare opportuni meccanismi per delimitare i dati prodotti da write( ) diverse

Page 279: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 34Andrea Corradini

TCP BUFFERING: STATO DEI BUFFERS

Se il ricevente esegue una read con un byte array di dimensione 4000, nella

situazione mostrata in figura, la read

• riempe completamente il byte array

• restituisce 1500 caratteri prodotti dalla seconda write( ) e 2500 dalla terza

• alcuni bytes rimangono nel receive buffer e verranno recuperati con

una successiva read( )

Page 280: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 35Andrea Corradini

TCP BUFFERING: USO DI WRITE( ) E READ( ) Supponiamo che il client spedisce una sequenza di byte con write( ) su di un

OutputStream, e il server legge la sequenza con delle read( ) dal corrispondente InputStream

Il client può riempire un array di byte buffer arbitrario e inviarlo con write(buffer): la write( ) blocca finché non ha scritto tutto. Può usare write(byte[ ] b, int off, int len) per spedire solo una porzione dell'array.

Il server può leggere usando un array di byte di grandezza arbitraria, MA DEVE CONTROLLARE SEMPRE QUANTI BYTE HA LETTO:

int read(byte [] buffer) restituisce il numero di byte letti, che può essere al massimo buffer.length, e -1 se lo stream è terminato dal sender.

int read(byte[] buffer, int offset, int length) analogo.

Page 281: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 36Andrea Corradini

TCP BUFFERING: RISCHIO DI DEADLOCK Meccanismo di Controllo del Flusso: quando il RecvQ è pieno, TCP impedisce

il trasferimento di ulteriori bytes dal corrispondente SendQ

Questo meccanismo può provocare situazioni di deadlock

La situazione di deadlock può essere generata nel caso di due programmi che si inviano simultaneamente grosse quantità di dati

Esempio: client e server si scambiano files di grosse dimensioni il receive buffer del server viene riempito così come il send buffer del

client l'esecuzione del client viene bloccata a causa di un'ulteriore write( ). il server non svuota il proprio receive buffer perchè bloccato, a sua

volta, nell'invio di una grossa quantità di dati al client

Page 282: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 37Andrea Corradini

SOCKETS: CHIUSURA• Un socket (oggetto della classe Socket) viene chiuso automaticamente:

– dal garbage collector, se non più raggiungibile

– alla terminazione del programma

• In certi casi (esempio un web browser)

– il numero di sockets aperti può essere molto alto

– il numero massimo di sockets supportati può essere raggiunto prima che la garbage collection ne elimini alcuni

– può essere necessario chiudere esplicitamente alcuni sockets che non vengono più utilizzati

– chiusura esplicita di un socket s : s.close( )

• E' buona prassi chiuderre i socket da programma quando non servono più

Page 283: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 38Andrea Corradini

SOCKETS: CHIUSURA

for (int i = 1; i< 1024; i++){

try { s = new Socket(host, i);

System.out.println("Esiste un servizio sulla porta" + i);

} catch (UnknownHostException ex){System.out.println("Host Sconosciuto");

} catch (IOException ex) {System.out.println("Non esiste un servizio sulla porta"+i);

} finally{try{ if (s!=null) {

s.close( ); s=null; System.out.println("chiuso");}

} catch(IOException ex){ }; } }

Page 284: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 39Andrea Corradini

SOCKETS: CHIUSURA ASIMMETRICA

• I metodi shutdownInput( ) e shutdownOutput( ) – consentono di chiudere indipendentemente gli stream di ingresso/

uscita associati al socket

• Esempio:

– un client non deve inviare ulteriori dati al socket, ma deve attendere una risposta dal socket stesso

– Il client può chiudere lo stream di output associato al socket e mantenere aperto lo stream di input per ricevere la risposta

• La lettura di un dato da un socket il cui corrispondente OutputStream è stato chiuso, restituisce il valore -1, che può essere quindi utilizzato come simbolo di fine sequenza

Page 285: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 40Andrea Corradini

Chiusura di una connessioneThree or Four ways handshake

• Una connessione TCP può essere chiusa in due modi: con un handshake a tre vie, in cui le due parti chiudono contemporaneamente le rispettive connessioni, o con uno a quattro vie, in cui le due connessioni vengono chiuse in tempi diversi.

• L'handshake a 3 vie è simile a quello usato per l'apertura della connessione, ma si usa il flag FIN invece del SYN. Un terminale invia un pacchetto con la richiesta FIN, l'altro risponde con un FIN + ACK, ed infine il primo manda l'ultimo ACK, e l'intera connessione viene terminata.

• L'handshake a 4 vie invece viene utilizzato quando la disconnessione non è contemporanea tra i due terminali in comunicazione. In questo caso uno dei due terminali invia la richiesta di FIN, e attende l'ACK. L'altro terminale farà poi altrettanto, generando quindi un totale di 4 pacchetti.

Page 286: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 41Andrea Corradini

ESERCIZIO; COMPRESSIONE DI FILE

Progettare un'applicazione client/server in cui il server fornisca un

servizio di compressione di dati.

Il client legge chunks di bytes da un file e li spedisce al server che

provvede alla loro compressione. Il server restituisce i bytes in formato

compresso al client che provvede a creare un file con lo stesso nome del

file originario e con estensione gz, che contiene i dati ricevuti dal server.

La comunicazione tra client e server utilizza il protocollo TCP.

Per la compressione si può utilizzare la classe JAVA GZIPOutputStream.

Individuare le condizioni necessarie affinchè il programma scritto generi

una situazione di deadlock e verificare che tale situazione si verifica

realmente quando tali condizioni sono verificate.

Page 287: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 42Andrea Corradini

STREAM MODE SOCKET API:INTERAZIONE CON SERVERS PREDEFINITI

Esercizio: considerare un servizio attivo su una porta pubblicata da un

Server (es 23 Telnet, 25 SMTP, 80 HTTP). Definire un client JAVA che

utilizzi tale servizio, dopo aver controllato che sia attivo.

Provare anche con i seguenti servizi (vedere JAVA Network Programming)

Daytime(porta 13): il client richiede una connessione sulla porta 13, il server invia la data e chiude la connessione

Echo (port 7): il client apre una connesione sulla porta 7 del server ed invia un messaggio. Il server restituisce il messaggio al client

Finger (porta 79): il client apre una connessione ed invia una query, il Server risponde alla query

Whois (porta 43): il client invia una stringa terminata da return/linefeed. La stringa può contenere, ad esempio, un nome. Il server invia alcune informazioni correlate a quel nome

Page 288: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 43Andrea Corradini

CLASSE SOCKET: OPZIONI

• la classe socket offre la possibilità di impostare diverse proprietà del

socket

• Proprietà:

– SO_TIMEOUT

– SO_RCVBUF

– SO_SNDBUF

– SO_KEEPALIVE

– TCP_NODELAY

– SO_LINGER

...........

Page 289: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 44Andrea Corradini

CLASSE SOCKET: SO_TIMEOUT

SO_TIMEOUT – consente di associare un time out al socket

if (s.getSoTimeout( ) == 0) s.setSoTimeout(1800000);

Il timeout viene specificato in millisecondi Quando eseguo una lettura bloccante dal socket, l'operazione si può

bloccare in modo indefinito

• SO_TIMEOUT: definisce un intervallo di tempo massimo per l'attesa dei dati

• Nel caso in cui il time out scada prima della ricezione dei dati, viene sollevata una eccezione

Page 290: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 45Andrea Corradini

CLASSE SOCKET: SO_RCVBUF, SO_SNDBUF SO_RCVBUF controlla la dimensione del buffer utilizzato per ricevere i dati.

– E' possibile impostare la dimensione del buffer di ricezione

sock.setReceiveBufferSize(4096) – La modifica non viene garantita su tutti i sistemi operativi– Per reperire la dimensione del buffer associato

int size = sock. getReceiveBufferSize( ) – Alternativa: utilizzare i BufferedInputStream/BufferedReader.

SO_SNDBUF : analogo per il buffer associato alla spedizione

int size = sock.getSendBufferSize( ); Attenzione: questi comandi non sono implementati correttamente su alcuni sistemi operativi

Page 291: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 46Andrea Corradini

CLASSE SOCKET: SO_KEEPALIVE

• So_keepalive: tecnica utilizzata per monitorare le connessioni aperte e controllare se il partner risulta ancora attivo

• introdotto per individuare i sockets “idle” su cui non sono stati inviati dati per un lungo intervallo di tempo

• Per default, su ogni socket vengono spediti solo dati inviati dalla applicazione

• Un socket può rimanere inattivo per ore, o anche per giorni– Esempio: crash di un client prima dell'invio di un segnale di fine

sequenza. In questo caso, il server può sprecare risorse (tempo di CPU, memoria,...) per un client che ha subito un crash

– Consente un'ottimizzazione delle risorse

Page 292: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 47Andrea Corradini

CLASSE SOCKET: SO_KEEPALIVE

sock.setSoKeepAlive(true) abilita il keep alive sul socket sock.

• il supporto invia periodicamente dei messaggi di keep alive sul socket per testare lo stato del partner.

• se il partner è ancora attivo, risponde mediante un messaggio di ack

• nel caso di mancata risposta viene reiterato l'invio del keep alive per un certo numero di volte

• se non si riceve alcun acknowledgment, il socket viene portato in uno stato di 'reset'

• ogni lettura, scrittura o operazione di chiusura su un socket posto in stato di reset(), solleva un'eccezione

• questa funzionalità può non essere implementata su alcune piattaforme, nel qual caso il metodo solleva un'eccezione

Page 293: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 48Andrea Corradini

CLASSE SOCKET: TCP_NODELAYServe per disabilitare l'algoritmo di Nagle, introdotto per evitare che il TCP

spedisca una sequenza di piccoli segmenti, quando la frequenza di invio dei dati da parte della applicazione è molto bassa

• L'algoritmo di Nagle riduce il numero di segmenti spediti sulla rete fondendo in un unico segmento più dati

• Applicazione originaria dell'algoritmo– Sessioni Telnet, in cui è richiesto di inviare i singoli caratteri

introdotti, mediante keyboard, dall'utente– Se l'algoritmo di Nagle non viene applicato, ogni carattere viene

spedito in un singolo segmento,(1 byte di data e decine di byte di header del messaggio)

• Motivazioni per disabilitare l'algoritmo di Nagle: trasmissioni di dati in 'tempo reale', ad esempio movimenti del mouse per un'applicazione interattiva come un gioco multiplayer.

Page 294: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 49Andrea Corradini

CLASSE SOCKET: TCP_NODELAY

Algoritmo di Nagle:

• In generale, per default, l'algoritmo di Nagle risulta abilitato

• tuttavia alcuni sistemi operativi disabilitano l'algoritmo di default

• per disabilitare l'algoritmo di Nagle

sock.setTcpNoDelay(true)

disabilita la bufferizzazione (no delay = non attendere, inviare subito un segmento, non appena l'informazione è disponibile)

• JAVA RMI disabilita l'algoritmo di Nagle: lo scopo è quello di inviare prontamente il segmento contenente i parametri di una call remota oppure il valore restituito dall'invocazione di un metodo remoto

Page 295: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 50Andrea Corradini

CLASSE SOCKET: SO_LINGER

La proprietà SO_LINGER (to linger = indugiare) viene utilizzata per

specificare cosa accade quando viene invocato il metodo close( ) su un

socket TCP.

A seconda del valore di SO_LINGER può accadere che

• Linger = false (default): il contenuto del buffer di invio associato al socket viene inviato al destinatario, mentre i dati nel buffer di ricezione vengono scartati. Il thread che esegue il metodo close( ) non attende la terminazione di queste attività che avvengono quindi in modo asincrono.

Questo è lo scenario di default, che però non garantisce che i dati vengano consegnati correttamente. In caso di crash del destinatario, ad esempio, i dati nel buffer di spedizione non vengono consegnati

Page 296: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 51Andrea Corradini

CLASSE SOCKET: SO_LINGER• Linger == true, Linger time == 0: Vengono scartati sia gli eventuali

dati nel buffer di ricezione che quelli da inviare. Come prima, lo scarto avviene in modo asincrono.– Utilizzato quando si vuole terminare la connessione

immediatamente, senza spedire i dati

• Linger == true e Linger time != 0: Vengono inviati eventuali dati presenti nel buffer al destinatario e si scartano gli eventuali dati nel buffer di ricezione. Il thread che esegue il metodo close( ) si blocca per il linger time oppure fino a che tutti i dati spediti sono stati confermati a livello TCP. Dopo linger time viene sollevata un'eccezione– Quando si vuole garantire che il metodo close( ) ritorni solo

quando i dati sono stati consegnati, oppure che sollevi un'eccezione nel caso in cui scatti il time-out definito da linger-time

Page 297: Java - Programmazione di Reti

Lezione 6: TCP: Stream Sockets 52Andrea Corradini

CLASSE SOCKET: SO_LINGER

public void setSoLinger (boolean no, int seconds) throws SocketException

public int getSoLinger ( ) throws SocketException

• per default, SO_LINGER = false: il supporto tenta di inviare i datagrams rimanenti, anche dopo che il socket è stato chiuso

• per controllare la gestione dei dati presenti al momento della chiusura

if (s.getSoLinger( ) == -1) s.setSoLinger(true, 240);

il metodo close( ) si blocca ed attende 240 secondi (4 minuti) prima

di eliminare i datagrams rimanenti. Se il tempo di attesa viene

impostato a 0, i datagram vengono eliminati immediatamente.

Page 298: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 1Andrea Corradini

Lezione n.8LPR-B-09

TCP Sockets & Multicast 24/11/2009

Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 299: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 2Andrea Corradini

Sommario

• Invio di oggetti tramite TCP con serializzazione (rischio di deadlock)

• Qualcosa sugli esercizi...

• Ancora sugli stream socket e su three-ways handshaking di TCP

• De-multiplexing di frammenti TCP

• Unreliable Multicast: concetti e API Java

• Panoramica su Linux Networking Tools (grazie a Daniele Sgandurra)

Page 300: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 3Andrea Corradini

INVIO DI OGGETTI SU CONNESSIONI TCP

• Per inviare oggetti su una connessione TCP basta usare la serializzazione: gli oggetti inviati devono implementare l'interfaccia Serializable

• Si possono usare i filtri ObjectInputStream / ObjectOutputStream per incapsulare gli stream ottenuti invocando getInputStream() / getOutputStream() sul socket

• Quando creo un ObjectOutputstream viene scritto lo stream header sullo stream. In seguito scrivo gli oggetti che voglio inviare sullo stream

• L'header viene letto quando viene creato il corrispondente ObjectInputStream

• L'invio/ ricezioni degli oggetti sullo/dallo stream avviene mediante scritture/letture sullo stream (writeObject(), readObject())

Page 301: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 4Andrea Corradini

INVIO DI OGGETTI SU UNA CONNESSIONE TCP

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; } }

Page 302: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 5Andrea Corradini

INVIO DI OGGETTI SU UNA CONNESSIONE TCP- LATO SERVER

import java.io.*; import java.net.*;

public class TCPObjectServer {

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","Rossi","Informatica");

output.writeObject(studente); output.writeObject("<Goodbye>");

clientsocket.close();

server.close();

} catch (Exception e) { System.err.println (e); } } }

Page 303: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 6Andrea Corradini

INVIO DI OGGETTI SU UNA CONNESSIONE TCP-LATO CLIENT

import java.io.*; import java.net.*;

public class TCPObjectClient { public static void main (String args[ ]) {

try { Socket socket = new Socket ("localhost", 3575);

ObjectInputStream in = new ObjectInputStream(socket.getInputStream());

String beginMessage = (String) in.readObject();

Studente stud = (Studente) in.readObject();

System.out.println(beginMessage);

System.out.print(stud.getMatricola() + " - " + stud.getNome() + " ");

System.out.println(stud.getCognome() + " - " + stud.getCorsoDiLaurea());

String endMessage = (String) in.readObject();

System.out.println (endMessage); socket.close();} catch (Exception e) { System.out.println (e); } } }

Page 304: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 7Andrea Corradini

INVIO DI OGGETTI SU UNA CONNESSIONE TCP- LATO CLIENT

Stampa prodotta lato Client

<Welcome>

14520 - Mario Rossi - Informatica

<Goodbye>

Page 305: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 8Andrea Corradini

OBJECT INPUT/OUTPUT STREAM: RISCHIO DI DEADLOCK

• La creazione dell'ObjectInputStream cerca di leggere lo header. Se questo non è stato ancora creato, si blocca.

• Quindi si verifica una situazione di deadlock se i due partner della connessione eseguono le istruzioni nel seguente ordine (s è il socket locale):

ObjectInputStream in = new ObjectInputStream(s.getInputStream( ));

ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream( ));

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 almeno uno dei partner

Page 306: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 9Andrea Corradini

ESERCIZIO: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.

Page 307: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 10Andrea Corradini

ESERCIZIO: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 una codifica testuale dei messaggi spediti tra client e

server oppure la serializzazione offerta da JAVA in modo da scambiare

oggetti tramite la connessione TCP

Page 308: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 11Andrea Corradini

Verso il MULTICAST:STRUTTURA GENERALE DI UN SOCKET

• remote port ed host significative solo per socket TCP

• SendQ, RecQ: buffer di invio/ricezione

• ogni socket è caratterizzato da informazioni sul suo stato (ad esempio closed). Lo stato del socket è visibile tramite il comando netstat

Page 309: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 12Andrea Corradini

CONNESSIONE LATO CLIENT: STATO DEL SOCKET

Quando il client invoca il costruttore Socket( ). • lo stato iniziale del socket viene impostato a Closed, la porta (P) e l'indirizzo locale (A.B.C.D) sono impostate dal supporto• dopo aver inviato il messaggio iniziale di handshake, lo stato del socket passa a SYN_SENT (inviato segmento SYN)• il client rimane bloccato fino a che il server riscontra il messaggio di handshake mediante un ack

Page 310: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 13Andrea Corradini

CONNESSIONE LATO SERVER: STATO DEL SOCKET

Il Server crea un server socket sulla porta Q• se non viene specificato alcun indirizzo IP (wildcard = *), il server può ricevere connessioni da una qualsiasi delle sue interfacce• lo stato del socket viene posto a Listening: questo indica che il server sta attendendo connessioni da una qualsiasi interfaccia, sulla porta Q

Page 311: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 14Andrea Corradini

CONNESSIONE LATO SERVER: STATO DEL SOCKET

• il server si sospende sul metodo accept( ) in attesa di una nuova connessione

• quando riceve una richiesta di connessione dal client, crea un nuovo socket. In tale socket

– indirizzo e porta remoti vengono inizializzati con l'indirizzo IP e la porta ricevuti dal client che ha richiesto la connessione

– L'indirizzo locale viene settato con l'indirizzo dell'interfaccia da cui è stata ricevuta la connessione.

– La porta locale viene inizializzata con quella a cui associata al server socket

• Quando il three-ways handshake è completato l'esecuzione del metodo accept( ) termina e restituisce un puntatore al socket creato, che viene inserito in una lista di socket associati al server socket.

Page 312: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 15Andrea Corradini

CREAZIONE DI CONNESSIONI LATO SERVER

Page 313: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 16Andrea Corradini

DEMULTIPLEXING DEI SEGMENTI TCP

• Quindi tutti i sockets associati allo stesso ServerSocket 'ereditano'

– la porta di ascolto

– l'indirizzo IP da cui è stata ricevuta la richiesta di connessione

• Questo implica che sullo stesso host possano esistere più sockets associati allo stesso indirizzo IP ed alla stessa porta locale (il Server Socket e tutti i Sockets associati,.....)

• Meccanismo di demultiplexing: utilizzato per decidere a quale socket è destinato un segmento TCP ricevuto su quella interfaccia e su quella porta

• La conoscenza dell'indirizzo e porta destinazione non risulta più sufficiente per individuare il socket a cui è destinato il segmento

Page 314: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 17Andrea Corradini

DEMULTIPLEXING DEI SEGMENTI TCP

Definizione del meccanismo di demultiplexing:

• La porta locale riferita nel socket deve coincidere con quella contenuta nel segmento TCP

• Ogni campo del socket contenente una wildcard (*), può essere messo in corrispondenza con qualsiasi valore corrispondente contenuto nel segmento

• Se esiste più di un socket che corrisponde al segmento in input, viene scelto il socket

che contiene il minor numero di wildcards.

• in questo modo un segmento spedito dal client viene ricevuto sul socket S associato alla connessione con quel client, piuttosto che sul serversocket perchè S risulta 'più specifico' per quel segmento

Page 315: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 18Andrea Corradini

GRUPPI DI PROCESSI: COMUNICAZIONE● Comunicazioni di tipo unicast = coinvolgono una sola coppia di processi● Ma diverse applicazioni di rete richiedono un tipo di comunicazione che

coinvolga un gruppo di hosts.

Applicazioni classiche usenet news: pubblicazione di nuove notizie ed invio di esse ad un gruppo

di hosts interessati videoconferenze: un segnale audio video generato su un nodo della rete

deve essere ricevuto dagli hosts associati ai partecipanti alla videoconferenza

Altre applicazioni massive multiplayer games: alto numero di giocatori che intergiscono in

un mondo virtuale DNS (Domain Name System): aggiornamenti delle tabelle di naming

inviati a gruppi di DNS, chats, instant messaging, applicazioni p2p

Page 316: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 19Andrea Corradini

GRUPPI DI PROCESSI: COMUNICAZIONE

Comunicazione tra gruppi di processi realizzata mediante multicasting(one to many communication).

Comunicazione di tipo multicast

un insieme di processi formano un gruppo di multicast

un messaggio spedito da un processo a quel gruppo viene recapitato a tutti gli altri partecipanti appartenenti al gruppo

Un processo può lasciare un gruppo di multicast quando non è più interessato a ricevere i messaggi del gruppo

Page 317: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 20Andrea Corradini

COMUNICAZIONE TRA GRUPPI DI PROCESSI

Multicast API: deve contenere primitive per

unirsi ad un gruppo di multicast (join). E’ richiesto uno schema di indirizzamento per identificare univocamente un gruppo.

lasciare un gruppo di multicast (leave).

spedire messaggi ad un gruppo. Il messaggio viene recapitato a tutti i processi che fanno parte del gruppo in quel momento

ricevere messaggi indirizzati ad un gruppo

Page 318: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 21Andrea Corradini

COMUNICAZIONE TRA GRUPPI DI PROCESSI:IMPLEMENTAZIONE

L’implementazione del multicast richiede:

uno schema di indirizzamento dei gruppi

un supporto che registri la corrispondenza tra un gruppo ed i partecipanti

un'implementazione che ottimizzi l’uso della rete nel caso di invio di pacchetti ad un gruppo di multicast

Page 319: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 22Andrea Corradini

MULTICAST: IMPLEMENTAZIONE

Server A invia un messaggio su un gruppo di multicast composto da 3

clients connessi allo stesso router (router2)

Server AServer A

Soluzione 1: router1 invia 3 messaggi con collegamenti di tipo unicast

Soluzione 2: router1 invia un unico messaggio.router2 replica il messaggio per i tre clients

router1

router2router2

router1

Page 320: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 23Andrea Corradini

MULTICAST: IMPLEMENTAZIONE

Ottimizzazione della banda di trasmissione: il router che riceve un pacchettodi multicast MP invia un unico pacchetto sulla rete. Il pacchetto viene replicatosolo quando è necessario.Esempio: pacchetto di multicast spedito da Milano agli hosts Hosta, HostB,HostC

MP MP

MPMilano

HostB HostC

MP MP

MP

Roma

Bologna

Firenze

Bari

PisaHost A

Page 321: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 24Andrea Corradini

INDIVIDUAZIONE GRUPPI DI MULTICAST

Indirizzo di multicast: indirizzo IP di classe D, che individua un gruppo di multicast

Indirizzo di classe D- intervallo 224.0.0.0 – 239-255-255-255

1110 …..

l’indirizzo di multicast è condiviso da tutti i partecipanti al gruppo

è possibile associare un nome simbolico ad un gruppo di multicast

Esempio: 224.0.1.1 ntp.mcast.net (network time protocol distributed service)

Page 322: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 25Andrea Corradini

INDIVIDUAZIONE GRUPPI DI MULTICAST

• Il livello IP (nei routers) mantiene la corrispondenza tra l’indirizzo di multicast e gli indirizzi IP dei singoli hosts che partecipano al gruppo di multicast

• Gli indirizzi possono essere:

Permanenti : l'indirizzo di multicast viene assegnato dalla IANA (Internet Assigned Numbers Authority).

L'indirizzo rimane assegnato a quel gruppo, anche se, in un certo istante non ci sono partecipanti

Temporanei : Esistono solo fino al momento in cui esiste almeno un partecipante. Richiedono la definizione di un opportuno protocollo per evitare conflitti nell'attribuzione degli indirizzi ai gruppi

Page 323: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 26Andrea Corradini

INDIVIDUAZIONE GRUPPI DI MULTICAST

• Gli indirizzi di multicast appartenenti all’intervallo

224.0.0.0 - 224.0.0.255

sono riservati per i protocolli di routing e per altre funzionalità a livello di rete

ALL-SYSTEMS.MCAST.NET 224.0.0.1 tutti gli host della rete locale

ALL-ROUTERS.MCAST.NET 224.0.0.2 tutti i routers della rete locale

• I routers non inoltrano mai i pacchetti che contengono questi indirizzi

• la maggior parte degli indirizzi assegnati in modo permanente hanno come prefisso 224.0, 224.1, 224.2, oppure 239

Page 324: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 27Andrea Corradini

MULTICAST ROUTERS

• Per poter spedire e ricevere pacchetti di multicast oltre i confini della rete locale, occorre disporre di un router che supporta il multicast (mrouter)

• Problema: disponbilità limitata di mrouters

• Per testare se la vostra rete è collegata ad un mrouter, dare il comando % ping all-routers.mcast.net

Se si ottiene una risposta, c'è un mrouter sulla sottorete locale. Routers che non supportano multicast, possono utilizzare la tecnica del

tunnelling = trasmissione di pacchetti multicast mediante unicast UDP

Page 325: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 28Andrea Corradini

CONNECTIONLESS MULTICAST

La comunicazione Multicast utilizza il paradigma connectionless

Motivazioni: gestione di un alto numero di connessioni richieste n(n-1) connessioni per un gruppo di n processi comunicazione connectionless adatta per il tipo di applicazioni verso cui è

orientato il multicast (trasmissione di dati video/audio).

• Esempio: invio dei frames di una animazione. E’ più accettabile la perdita occasionale di un frame piuttosto che un ritardo costante tra la spedizione di due frames successivi

Page 326: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 29Andrea Corradini

UNRELIABLE VS. RELIABLE MULTICAST

Unreliable Multicast (multicast non affidabile):

• non garantisce la consegna del messaggio a tutti i processi che partecipano al gruppo di multicast.

• unico servizio offerto dalla multicast JAVA API standard (esistono package JAVA non standard che offrono qualche livello di affidabilità)

Reliable Multicast (multicast affidabile):

• garantisce che il messaggio venga recapitato una sola volta a tutti i processi del gruppo

• può garantire altre proprietà relative all’ordinamento con cui i messaggi spediti al gruppo di multicast vengono recapitati ai singoli partecipanti

Page 327: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 30Andrea Corradini

MULTICAST API DI JAVA: MulticastSocket

MulticastSocket = socket su cui spedire/ricevere i messaggi verso/da un gruppo di multicast la classe MulticastSocket estende la DatagramSocket con alcune

funzionalità utili per il multicast

il ricevente deve creare un MulticastSocket su una determinata porta, iscrivere il socket al gruppo, e fare una receive.

il mittente deve inviare il messaggio (un DatagramPacket) specificando il gruppo e una porta.

il messaggio è ricevuto da tutti i MulticastSocket iscritti al gruppo e che stanno ricevendo sulla porta indicata.

Page 328: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 31Andrea Corradini

MULTICAST: L’API JAVA

Uso delle porte per multicast sockets:Unicast • IP Address individua un host, • porta individua un servizioMulticast• IP Address individua un gruppo di hosts, • porta consente di partizionare dati di tipo diverso inviati allo stesso

gruppo

Gruppo dimulticast

invio dati

Host1

50004000

….

5000

4000 Host2

Esempio: porta 5000 traffico audio, porta 4000 traffico video

Page 329: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 32Andrea Corradini

MULTICAST API DI JAVA: il receiverimport java.net.*;

public class MulticastTestReceiver{

public static void main (String [ ] args) throws Exception{InetAddress group = InetAddress.getByName(args[0]); // gruppoif (!group.isMulticastAddress()){ // controllo se è multicast

throw new IllegalArgumentException();}int port = Integer.parseInt(args[1]); // porta localeMulticastSocket ms = new MulticastSocket(port);ms.joinGroup (group); // mi iscrivo al gruppoDatagramPacket dp = new DatagramPacket(new byte[8192], 8192);ms.receive(dp); // ricevo e stampoSystem.out.println(new String(dp.getData(),0,dp.getLength())); }}

Page 330: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 33Andrea Corradini

MULTICAST API DI JAVA: il senderimport java.net.*;

public class MulticastTestSender{

public static void main (String [ ] args) throws Exception{InetAddress group = InetAddress.getByName(args[0]); // gruppoif (!group.isMulticastAddress()){ // controllo se è multicast

throw new IllegalArgumentException(); }int port = Integer.parseInt(args[1]); // porta destinatariaSystem.out.println("String to send? ");byte [] data = Input.readLine().getBytes();DatagramPacket dp = // creo il pacchetto

new DatagramPacket(data, data.length, group, port);MulticastSocket ms = new MulticastSocket();ms.setTimeToLive(5); ms.send(dp); }} // spedisco

Page 331: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 34Andrea Corradini

MULTICAST: più socket sulla stessa porta

Una porta non individua un servizio (processo) su un certo host:• Se attivo due istanze di MulticastTestReceiver sullo stesso host e sulla

stessa porta non viene sollevata una BindException (che viene invece sollevata se MulticastSocket è sostituito da un DatagramSocket)

Page 332: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 35Andrea Corradini

MULTICAST SNIFFER

• Il programma riceve in input il nome simbolico di un gruppo di multicast si unisce al gruppo e 'sniffa' i messaggi spediti su quel gruppo, stampandone il contenuto

import java.net.*; import java.io.*;

public class MulticastSniffer {

public static void main (String[] args){InetAddress group = null; // indirizzo del gruppoint port = 0; // porta localetry{group = InetAddress.getByName(args[0]);

port = Integer.parseInt(args[1]);} catch(Exception e){System.out.println("Uso: " +

"java multicastsniffer multicast_address port"); System.exit(1); }

Page 333: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 36Andrea Corradini

MULTICAST SNIFFER

MulticastSocket ms = null;

try{ ms = new MulticastSocket(port);

ms.joinGroup(group); // mi unisco al gruppo

byte [ ] buffer = new byte[8192];

while (true){DatagramPacket dp = new DatagramPacket(buffer, buffer.length);ms.receive(dp); // aspetto un pacchettoString s = new String(dp.getData()); // estraggo il messaggioSystem.out.println(s);} // .lo stampo

} catch (IOException ex){System.out.println (ex);

}

Page 334: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 37Andrea Corradini

MULTICAST SNIFFER

finally{ // in ogni caso...

if (ms != null) { // se avevo aperto il multicast sockettry{

ms.leaveGroup(group); // lascio il gruppoms.close(); // chiudo il socket

} catch (IOException ex){}

}}}}

Page 335: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 38Andrea Corradini

MULTICAST: TIME TO LIVE

• IP Multicast Scoping: meccanismo utilizzato per limitare la diffusione sulla rete di un pacchetto inviato in multicast

• ad ogni pacchetto IP viene associato un valore rappresentato su un byte, riferito come TTL (Time-To-Live) del pacchetto

• TTL assume valori nell’intervallo 0-255

• TTL indica il numero massimo di routers che possono essere attraversati dal pacchetto

• il pacchetto viene scartato dopo aver attraversato TTL routers

• meccanismo introdotto originariamente per evitare loops nel routing dei pacchetti

Page 336: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 39Andrea Corradini

MULTICAST: TIME TO LIVE

Internet Scoping, implementazione

il mittente specifica un valore per del TTL per i pacchetti spediti

il TTL viene memorizzato in un campo dell’header del pacchetto IP

TTL viene decrementato da ogni router attraversato

Se TTL = 0 ⇒ il pacchetto viene scartato

Page 337: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 40Andrea Corradini

MULTICAST: TIME TO LIVE

Valori consigliati per il ttl

Destinazione Valori di ttl processi sullo stesso host 0 processi sulla stessa sottorete locale 1 processi su reti locali gestite dallo stesso router 16

processi allocati su un generico host di Internet 255

Page 338: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 41Andrea Corradini

TIME TO LIVE: API JAVA

• Assegna il valore di default = 1 al TTL ( i pacchetti di multicast non possono lasciare la rete locale)

• Per modificare il valore di default: posso associare il ttl al multicast socket

MulticastSocket s = new MulticastSocket( );

s.setTimeToLive(16);

Page 339: Java - Programmazione di Reti

Lezione 8: TCP Sockets e Multicast 42Andrea Corradini

MULTICAST: ESERCIZIO

Definire un Server TimeServer, che invia su un gruppo di multicast

dategroup, ad intervalli regolari,la data e l’ora. L’attesa tra un invio ed il

successivo può essere simulata mediante il metodo sleep( ). L’indirizzo IP

di dategroup viene introdotta linea di comando.

Definire quindi un client TimeClient che si unisce a dategroup e riceve, per

dieci volte consecutive, data ed ora, le visualizza, quindi termina.

Page 340: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 1Andrea Corradini

Lezione n.9LPR-B-09

RMI: Remote Method Invocation 1/12/2009

Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 341: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 2Andrea Corradini

Da UDP/TCP a RPC/RMI

• I protocolli visti (UDP, TCP) permettono a processi su host diversi di scambiarsi dati, più o meno strutturati: sequenze di byte dati primitivi oggetti (con serializzazione)

• In molte applicazioni distribuite il livello di astrazione dei socket, non è adeguato.

• Il paradigma Remote Procedure Call (RPC) permette di astrarre da questi concetti: un programma può eseguire del codice su un host remoto con una normale chiamata di procedura.

• Nel contesto Object Oriented una “procedura” corrisponde a un metodo; in Java si parla quindi di Remote Method Invocation (RMI).

Page 342: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 3Andrea Corradini

RPC/RMI: PARADIGMA DI INTERAZIONE A DOMANDA/RISPOSTA

Paradigma di interazione basato su richiesta/risposta• il client invia ad un server un messaggio di richiesta (invocazione di

procedura/metodo)• il server risponde con un messaggio di risposta (risultato)• il client rimane bloccato finchè non riceve la risposta dal server

Client Server

Bloccato In elaborazione

richiesta

risposta

Page 343: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 4Andrea Corradini

REMOTE PROCEDURE CALL: ESEMPIO

PROCESSO CLIENT PROCESSO SERVER

print (msg)

proceduraremota print(…)

codice

bloccato

Esempio: richiesta stampa di messaggio e restituzione esito operazione

Page 344: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 5Andrea Corradini

Esempi di Remote Procedure Call

Possibili esempi in cui RPC è utile:

• Esecuzione su un server molto potente di codice molto complesso

• Esecuzione su host remoto di interrogazioni su database, compreso

elaborazione parziale dei risultati (es: media salari impiegati, ...)

• In generale, distribuzione del carico computazionale di un programma

CPU-intensive tra più host

• Multiplayer games con stato centralizzato su di un server

Page 345: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 6Andrea Corradini

RPC: schema generale di implementazione

• Il server implementa delle procedure (metodi) e li offre come procedure remote tramite un'interfaccia

• Per invocare una procedura remota del server, il client si procura un handle (“maniglia”), una specie di rappresentazione locale della procedura

• L'invocazione comprende: – marshalling dei parametri; – spedizione al server; – unmarshalling; – invocazione della procedura.

• Il ritorno comprende: – marshalling del risultato; – spedizione al client; – unmarshalling; – consegna del valore di ritorno.

Page 346: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 7Andrea Corradini

RPC tra piattaforme eterogenee• Se client e server sono scritti in linguaggi arbitrari, eventualmente

diversi e su piattaforme diverse, per realizzare RPC bisogna: fissare un formato per lo scambio di dati, per esempio XDR

(eXternal Data Representation) fornire traduzione tra formato nativo e formato di scambio

• Strumenti per il supporto di RPC: IDL (Interface Description Language) Compilatore

IDL -> Stub (lato client)– procedura che sostituisce quella del server

implementando marshalling e unmarshalling IDL -> Skeleton (lato server)

– routine che realizza unmarshalling dei paramentri, invocazione della procedura, marshalling del risultato

Page 347: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 8Andrea Corradini

USER VIEW

Si crea un handle della procedura:ProcedureHandle = lookup(registro, “nome”);

Successivamente si invoca la procedura:result = ProcedureHandle(param1, param2, ...);

Queste semplici operazioni sostituiscono: apertura di connessione con host remoto spedizione dei parametri ricezione del risultato e sua memorizzazione ... oltre all'implementazione del server remoto...

Page 348: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 9Andrea Corradini

RPC NEL PARADIGMA ORIENTATO AD OGGETTI

Implementazioni RPC • Open Network Computing Remote Procedure Call (Sun)• Open Group Distributed Computing Environment (DCE)• …

• Nel contesto della Programmazione Orientata ad Oggetti, naturale evoluzione di RPC:

procedure remote => oggetti remoti chiamata di procedura => invocazione di metodo

• CORBA (Common Object Request Broker Architecture)) è un'architettura che supporta RPC in contesto OO tra sistemi eterogenei (es: Java e C++)

• JAVA RMI: API Java per la programmazione distribuita ad oggetti. Sfrutta il fatto che client e server sono entrambi in Java.

Page 349: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 10Andrea Corradini

OGGETTI REMOTI: ARCHITETTURA GENERALE

Object Registry

Client ServerOggetto remoto

Esportazione (registrazione)

Server Proxy

Riferimento all’oggetto remoto

Invocazione metodi

Interazione logicaInterazione fisica

Client Proxy

Network Support Network Support

Page 350: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 11Andrea Corradini

RMI: ARCHITETTURA LATO SERVER

Il server che definisce l’oggetto remoto:

• definisce un'interfaccia remota che contiene i metodi remoti che possono essere invocati da parte di processi in esecuzione su hosts remoti

• crea un oggetto che implementa l'interfaccia remota, lo esporta per farlo diventare un “RMI server”, e lo pubblica in un registry (registro) associandolo a un nome simbolico

• i metodi remoti invocati da client diversi sono eseguiti concorrentemente, se non sono sincronizzati.

• Importante la separazione tra interfaccia pubblica e implementazione (privata)

Page 351: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 12Andrea Corradini

RMI: ARCHITETTURA LATO CLIENT

• Quando il client vuole accedere all’oggetto remoto ricerca un riferimento all’oggetto remoto mediante i servizi offerti dal registry operazione di lookup il cliente deve conoscere

host su cui è eseguito il registry nome simbolico pubblicato nel registry per l'oggetto

il risultato del lookup è un oggetto (handle) il cui tipo è l'interfaccia remota implementata dall'oggetto remoto

sullo handle ottenuto il cliente invoca i metodi definiti dall’oggetto remoto (remote method invocation).

Page 352: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 13Andrea Corradini

RMI: JAVA API lato Server

• Interfaccia remota: extends java.rmi.Remote (marker interface)

• Nell'implementazione dell'oggetto remoto i metodi invocabili da remoto devono prevedere il lancio di

java.rmi.RemoteException

• Per esportare l’oggetto remoto e farlo diventare “sever RMI”, due tecniche: extends UnicastRemoteObject nella dichiarazione della classe

che definisce l'oggetto remoto oppure prima della pubblicazione si usa il metodo statico

UnicastRemoteObject.exportObject(Object); bisogna prima creare la classe dello stub usando

> rmic ClasseOggettoRemoto

Page 353: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 14Andrea Corradini

RMI: JAVA API lato Server II

• Pubblicazione dell'oggetto: crea un binding (associazione)

nome simbolico oggetto/ riferimento all’oggetto lo pubblica mediante un servizio di tipo registry (registro)

(simile ad un DNS per oggetti distribuiti)

• Attivazione del RMI registry (porta default 1099): rmiregistry & (Linux) start rmiregistry (Windows)

Page 354: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 15Andrea Corradini

RMI: JAVA API lato Server II

• Accesso al registro usando la classe java.rmi.Naming void Naming.bind(String name, Remote obj) void Naming.rebind(String name, Remote obj) Remote Naming.lookup(String name)

name ha la forma “//host:port/nome”, con host e port opzionali e default “//localhost:1099/”.

• Accesso al registro usando la classe java.rmi.LocateRegistry Registry LocateRegistry.getRegistry([String host], [int port])

restituisce un riferimento al registro, sul quale posso invocare i metodi bind(), rebind(), lookup(), list(), unbind()

Page 355: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 16Andrea Corradini

ESEMPIO DI REMOTE INTERFACE

Esempio: un Host è connesso ad una stazione metereologica che rilevatemperatura, umidità,….mediante diversi strumenti di rilevazione. Sull’host èin esecuzione un server che fornisce queste informazioni agli utentiinteressati. L'interfaccia remota potrebbe essere la seguente:

import java.rmi.*;

public interface weather extends Remote{

public double getTemperature ( ) throws RemoteException;

public double getHumidity ( ) throws RemoteException;

public double getWindSpeed ( ) throws RemoteException;

}

Page 356: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 17Andrea Corradini

ESEMPIO RMI: un servizio di ECHO

Definiamo un oggetto remoto che fornisce un servizio di echo,cioè ricevuto un valore come parametro, restituisce al chiamante lostesso valore

• Passo 1. Definire una interfaccia che includa le firme dei metodi che possono essere invocati da remoto

• Passo 2. Definire una classe che implementi l'interfaccia. Questa classe include l'implementazione di tutti i metodi che possono essere invocati da remoto

Page 357: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 18Andrea Corradini

Passo1. Definizione dell'interfaccia

import java.rmi.*;

public interface EchoInterface extends Remote {

String getEcho (String Echo) throws RemoteException; }

Passo2. Implementazione dell'interfaccia

public class Server implements EchoInterface {

public Server( ) { } public String getEcho (String echo) throws RemoteException;

{return echo ; } } la classe può definire ulteriori metodi pubblici, ma solamente quelli

definiti nella interfaccia remota possono essere invocati da un altro host

ESEMPIO RMI: un servizio di ECHO

Page 358: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 19Andrea Corradini

Passo 3. Creare, esportare e pubblicare un'istanza dell'oggetto remoto

import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry;

import java.rmi.server.UnicastRemoteObject;

public class ServerActivate{

public static void main(String args[]) {

try { Server obj = new Server( );

EchoInterface stub = (EchoInterface)

UnicastRemoteObject.exportObject(obj);

Registry registry = LocateRegistry.getRegistry ( );

registry.bind ("Echo", stub); System.err.println("Server ready");

} catch (Exception e) {

System.err.println("Server exception: " + e.toString()); }}}

ESEMPIO RMI: un servizio di ECHO

Page 359: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 20Andrea Corradini

CREAZIONE E PUBBLICAZIONE DELL'OGGETTO REMOTO

Il server

• crea un'istanza dell'oggetto (new)

• invoca il metodo statico UnicastRemoteObject.exportObject(obj) che– esporta l'oggetto remoto obj creato in modo che le invocazioni ai suoi

metodi possano essere ricevute su una porta anonima. – restituisce lo stub dell'oggetto remoto. Il client deve reperire questo

stub per poter invocare i metodi remoti

• NOTA BENE: la classe dello stub deve essere creata prima esplicitamente, mediante il comando rmic (rmi compiler): > rmic Server

• dopo aver eseguito il metodo, sulla porta anonima individuata, un server RMI aspetta invocazioni di metodi remoti su un ServerSocket

• Lo stub generato (da passare al client) contiene indirizzo IP e porta su cui è attivo il server RMI

Page 360: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 21Andrea Corradini

CREAZIONE DELLO STUB

• Per invocare i metodi dell'oggetto remoto, il client deve avere a disposizione lo stub dell'oggetto

• Stub = contiene uno scheletro per ogni metodo definito nell'interfaccia (con le solite segnature), ma trasforma l'invocazione di un metodo in una richiesta a un host remoto (a una porta opportuna)

• Il client deve reperire lo stub e utilizzarlo per invocare i metodi remoti

• JAVA mette a disposizione del programmatore un semplice name server (registry) che consente

– Al server di registrare lo stub con un nome simbolico– Al client di reperire lo stub tramite il suo nome simbolico

Page 361: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 22Andrea Corradini

JAVA : ESPORTAZIONE DELLO STUB

• Il Server per rendere disponibile lo stub creato agli eventuali clients, inserisce un riferimento allo stub creato in un registry. Normalmente useremo il registry locale, che deve essere attivo sul localhost sulla porta di default 1099 (altrimenti va attivato come visto prima).

Registry registry = LocateRegistry.getRegistry( );

registry.bind ("Echo", stub);• Registry = simile ad un DNS per oggetti remoti, contiene legami tra il

nome simbolico dell’oggetto remoto ed il riferimento all’oggetto

echoriferimento all’oggetto

nome servizio riferimento

Page 362: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 23Andrea Corradini

JAVA: IL REGISTRY

• la classe LocateRegistry contiene metodi per la gestione dei registry

• La getRegistry( ) restituisce un riferimento ad un registry allocato sull'host locale e sulla porta di default 1099

• Si può anche specificare il nome di un host e/o una porta per individuare il servizio di registry su uno specifico host e/o porta

public static Registry getRegistry(String host, int port)

throws RemoteException

• nel caso più semplice si utilizza un registry locale, attivato sullo stesso host su cui è in esecuzione il server

• se non ci sono parametri oppure se il nome dell'host è uguale a null, allora l'host di riferimento è quello locale

Page 363: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 24Andrea Corradini

JAVA : IL REGISTRY

Supponiamo che registry sia l'istanza di un registro individuato mediantegetregistry( )

• registry.bind ( ) crea un collegamento tra un nome simbolico (qualsiasi) ed un riferimento all’oggetto. Se esiste già un collegamento per lo stesso oggetto all’interno dello stesso registry, viene sollevata una eccezione

• registry.rebind ( ) crea un collegamento tra un nome simbolico (qualsiasi) ed un riferimento all’oggetto. Se esiste già un collegamento per lo stesso oggetto all’interno dello stesso registry, tale collegamento viene sovrascritto

• è possibile inserire più istanze dello stesso oggetto remoto nel registry, con nomi simbolici diversi

Page 364: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 25Andrea Corradini

JAVA: ATTIVAZIONE DEL SERVIZIO

Per rendere disponibile i metodi dell’oggetto remoto, è necessario attivaredue tipi di servizi• il server registry che fornisce il servizio di registrazione di oggetti

remoti • Il server implementato fornisce accesso ai metodi remoti

Attivazione del registry in background:$ rmiregistry & (in LINUX)$ start rmiregistry (in WINDOWS)

• viene attivato un registry associato per default alla porta 1099• Se la porta è già utilizzata, viene sollevata un’eccezione. Si può anche

scegliere esplicitamente una porta$ rmiregistry 2048 &

Page 365: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 26Andrea Corradini

RMI REGISTRY

• Il registry viene eseguito per default sulla porta 1099

• Se si vuole eseguire il registry su una porta diversa, occorre specificare il numero di porta da linea di comando, al momento dell'attivazione

start rmiregistry 2100

• la stessa porta va indicata sia nel client che nel server al momento del reperimento del riferimento al registro, mediante LocateRegistry.getRegistry

Registry registry = LocateRegistry.getRegistry(2100);

• NOTA BENE: il registry ha bisogno dell'interfaccia e dei .class, per cui attenti acome sono impostati i path!

Page 366: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 27Andrea Corradini

IL CLIENT RMI

Il client:• ricerca uno stub per l'oggetto remoto• invoca i metodi dell’oggetto remoto come fossero metodi locali (l'unica

differenza è che occorre intercettare RemoteException)

Per ricercare il riferimento allo stub, il client

• deve accedere al registry attivato sul server.

• il riferimento restituito dal registry è un riferimento ad un oggetto di tipo Object: è necessario effettuare il casting dell’oggetto restituito al tipo definito nell’interfaccia remota

Page 367: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 28Andrea Corradini

IL CLIENT RMI

import java.rmi.registry.LocateRegistry;

import java.rmi.registry.Registry;

import java.util.*;

public class Client {

private Client( ) { }

public static void main(String[ ] args) throws Exception

{

String host = args[0];

Scanner s = new Scanner(System.in);

String next = s.next();

Page 368: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 29Andrea Corradini

IL CLIENT RMI

try {

Registry registry = LocateRegistry.getRegistry(host);

EchoInterface stub = (EchoInterface) registry.lookup("Echo");

String response = stub.getEcho(next);

System.out.println("response: " + response);

} catch (Exception e) {

System.err.println("Client exception: " + e.toString());

e.printStackTrace();

}}}

Page 369: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 30Andrea Corradini

ESEMPIO: FIBONACCI

• Il server calcola il numero di Fibonacci per numeri di grandezza arbitraria.

• Rispetto all'esempio Echo, questo esempio usa API più semplici per esportare e pubblicare l'oggetto remoto.

L'Interfaccia Remota

import java.rmi.*;

import java.math.BigInteger;

public interface RemoteFibonacci extends Remote {

public BigInteger getFibonacci(BigInteger n) throws RemoteException;

}

Page 370: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 31Andrea Corradini

ESEMPIO: FIBONACCI - L'OGGETTO REMOTO

import java.rmi.*; import java.rmi.server.UnicastRemoteObject;

import java.math.BigInteger;

public class FibonacciImpl extends UnicastRemoteObject implements

RemoteFibonacci {

public FibonacciImpl( ) throws RemoteException {

super( );

}

public BigInteger getFibonacci(BigInteger n) throws RemoteException {

System.out.println("Calculating the " + n + "th Fibonacci number");

//CONTINUA

Page 371: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 32Andrea Corradini

ESEMPIO: FIBONACCI - L'OGGETTO REMOTO

// Continua...BigInteger zero = new BigInteger("0");BigInteger one = new BigInteger("1");if (n.equals(zero)) return one;if (n.equals(one)) return one; BigInteger i = one, low = one, high = one; while (i.compareTo(n) == -1) {

BigInteger temp = high;high = high.add(low);low = temp; i = i.add(one);

}

return high; }}

Page 372: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 33Andrea Corradini

ESEMPIO: FIBONACCI - PUBBLICAZIONE

import java.net.*; import java.rmi.*;

public class FibonacciServer {

public static void main(String[] args) {try {

FibonacciImpl f = new FibonacciImpl( );Naming.rebind("fibonacci", f);System.out.println("Fibonacci Server ready.");

} catch (RemoteException rex) {System.out.println("Exception in FibonacciImpl.main: " + rex);} catch (MalformedURLException ex) {System.out.println("MalformedURLException " + ex);}

}}

Page 373: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 34Andrea Corradini

ESEMPIO: FIBONACCI - IL CLIENT

import java.rmi.*; import java.net.*; import java.math.BigInteger;

public class RemoteFibonacciClient {

public static void main(String args[]) {

if (args.length == 0 || !args[0].startsWith("rmi:")) {System.err.println("Usage: java FibonacciClient " +

" rmi://host.domain:port/fibonacci number"); return; }

try {Object o = Naming.lookup(args[0]);RemoteFibonacci calculator = (RemoteFibonacci) o;for (int i = 1; i < args.length; i++) {

try {BigInteger index = new BigInteger(args[i]);BigInteger f = calculator.getFibonacci(index);System.out.println("The " + args[i] + "th Fibonacci number is " + f); }

Page 374: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 35Andrea Corradini

ESEMPIO: FIBONACCI - IL CLIENT

catch (NumberFormatException e) {System.err.println(args[i] + "is not an integer.");

}}

} catch (MalformedURLException ex) {System.err.println(args[0] + " is not a valid RMI URL");

} catch (RemoteException ex) {System.err.println("Remote object threw exception " + ex);

} catch (NotBoundException ex) {System.err.println("Could not find the requested remote object on the server");

}

}}

Page 375: Java - Programmazione di Reti

Lezione 9: RMI - Remote Method Invocation 36Andrea Corradini

ESERCIZIO

Sviluppare una applicazione RMI per la gestione di un’elezione. Il serveresporta un insieme di metodi

• public void vota (String nome). Accetta come parametro il nome del candidato. Non restituisce alcun valore. Registra il voto di un candidato in una struttura dati opportunamente scelta.

• public int risultato (String nome) Accetta come parametro il nome di un candidato e restituisce i voti accumulati da tale candidato fino a quel momento.

• un metodo che consenta di ottenere i nomi di tutti i candidati, con i rispettivi voti, ordinati rispetto ai voti ottenuti

Page 376: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 1Andrea Corradini

Lezione n.10LPR-B-09

RMI CallBacks 9/12/2009

Andrea Corradini

Università degli Studi di Pisa Dipartimento di Informatica

Page 377: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 2Andrea Corradini

RMI: PASSAGGIO DI PARAMETRI

Nell'invocazione di un metodo con RMI, i parametri vengono passati nel seguente modo:

parametri di tipo primitivo vengono passati per valore

parametri di tipo riferimento vengono serializzati e il server ne crea una copia– Qundi una modifica fatta dal server non è visibile dal client

parametri di tipo “remoto” vengono passati come riferimenti

Page 378: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 3Andrea Corradini

Meccanismo RMI prevede: comunicazione unidirezionale (dal client al server) comunicazione sincrona, rendez-vouz esteso: il client invoca un

metodo remoto e si blocca finchè il metodo non termina

Ma in molte applicazioni il client è interessato ad un evento che si verifica sul server e

notifica il suo interesse al server (per esempio utilizzando RMI) il server registra che il client è interessato in quell’evento quando l’evento si verifica, il server notifica ai clients interessati

l’accadimento dell’event

IL MECCANISMO DELLE CALLBACK: MOTIVAZIONI

Page 379: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 4Andrea Corradini

IL MECCANISMO DELLE CALLBACK: MOTIVAZIONI

Esempi di applicazioni:

Un utente partecipa a un gruppo di discussione (es: Facebook) e vuol essere avvertito quando un nuovo utente entra nel gruppo.

Lo stato di un gioco multiplayer viene gestito da un server. I giocatori notificano al server le modifiche allo stato del gioco. Ogni giocatore deve essere avvertito quando lo stato del gioco subisce delle modifiche.

Gestione distribuita di un’asta: un insieme di utenti partecipa ad un’asta distribuita. Ogni volta che un utente fa una nuova offerta, tutti i partecipanti all’asta devono essere avvertiti.

Page 380: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 5Andrea Corradini

• Come può essere avvisato il client che un evento si è verificato sul server?

Polling: il client interroga ripetutamente il server, per sapere se si è verificato l’evento atteso. L’interrogazione può avviene tramite mediante RMI Svantaggio: inefficiente, spreco di risorse del sistema

Registrazione dei clients interessati agli eventi e successiva notifica (asincrona) del verificarsi dell’evento al client da parte del server Problema: quale meccanismo può usare il server per avvisare

il client?

IL MECCANISMO DELLE CALLBACK: MOTIVAZIONI

Page 381: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 6Andrea Corradini

RMI: IL MECCANISMO DELLE CALLBACK

• Il meccanismo delle callback permette di utilizzare RMI sia per l’invocazione client-server (registrazione del client) che per quella server-client (notifica del verificarsi di un evento).

• Come funziona? Il server definisce un'interfaccia remota ServerInterface con un

metodo remoto che serve al client per registrarsi Il client definisce un'interfaccia remota ClientInterface che

definisce un metodo remoto usato dal server per notificare un evento al client

Il client conosce la ServerInterface e ottiene il puntatore all'oggetto remoto tramite il registry

Page 382: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 7Andrea Corradini

Il client invocando il metodo remoto per registrarsi passa al server un riferimento RC a un oggetto che implementa la ClientInterface

Il server memorizza RC in una sua struttura dati (ad esempio, un Vector)

Quando deve notificare, il server utilizza RC per invocare il metodo remoto di notifica definito dal client.

In questo modo si rende ‘simmetrico’ il meccanismo di RMI, ma… il client non registra l’oggetto remoto in un rmiregistry, ma

passa un riferimento a tale oggetto al server, al momento della registrazione

RMI: IL MECCANISMO DELLE CALLBACK

Page 383: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 8Andrea Corradini

Da Wikipedia: “In programmazione una callback è una funzione specializzata che viene passata come parametro a un'altra funzione (che invece è generica). Questo permette alla funzione generica di compiere un lavoro specifico attraverso la callback.”

Esempio: la funzione generica quicksort prende come argomento l'array da ordinare e una funzione callback per confrontare gli elementi.

Nel contesto Object Oriented, una callback è un'istanza che fornisce un'implementazione di un metodo specificato in un'interfaccia.

Esempio nelle API Java: Uso di Comparator nei metodi di sorting della classe Arrays

CHE SIGNIFICA “CALLBACK”?

Page 384: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 9Andrea Corradini

CALLBACKS: UN ESEMPIO

Lato Server: Interfaccia remota che definisce metodi per: (1) Contattare il

server: metodo SayHello( ) (2) Registrare/cancellare una callback:

c

Implementazione dell'interfaccia Esportazione e pubblicazione su registry di oggetto remoto

Lato Client: Intefaccia remota che definisce metodo remoto (callback) Implementazione di interfaccia remota Programma principale che:

Registra una callback presso il server: sarà usata per notificare al client i contatti stabiliti da clients con il metodo SayHello( ).

Effettua un numero casuale di richieste del metodo SayHello( ) Cancella la propria registrazione

Page 385: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 10Andrea Corradini

L'INTERFACCIA REMOTA DEL SERVER

import java.rmi.*;

public interface CbServerInt extends Remote {

/* metodo di notifica */

public String sayHello(String name) throws RemoteException;

/* registrazione per il callback */

public void registerForCallback(CbClientInt callbackClient)throws RemoteException;

/* cancella registrazione per il callback */

public void unregisterForCallback(CbClientInt callbackClient)throws RemoteException;

}

Page 386: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 11Andrea Corradini

L'IMPLEMENTAZIONE DEL SERVER

import java.rmi.*; import java.rmi.server.*;import java.util.*;

public class CbServerImpl extends UnicastRemoteObject

implements CbServerInt{

/* lista dei client registrati */

private List<CbClientInt> clients;

/* crea un nuovo servente */

public CbServerImpl( ) throws RemoteException {clients = new ArrayList<CbClientInt>( );

}

/* continua */

Page 387: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 12Andrea Corradini

L'IMPLEMENTAZIONE DEL SERVER

public synchronized void registerForCallback(CbClientInt callbackClient)

throws RemoteException{ if (!clients.contains(callbackClient)) {

clients.add(callbackClient); }System.out.println(" New client registered." ); }

/* annulla registrazione per il callback */

public synchronized void unregisterForCallback(CbClientInt callbackClient)

throws RemoteException{if (clients.remove(callbackClient)) {

System.out.println("Client unregistered");}else{

System.out.println("Unable to unregister client."); }}

Page 388: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 13Andrea Corradini

L'IMPLEMENTAZIONE DEL SERVER /* metodo di notifica

* quando viene richiamato, fa il callback a tutti i client registrati */

public String sayHello (String name) throws RemoteException {doCallbacks(name);return "Hello, " + name + "!"; }

private synchronized void doCallbacks(String name) throws RemoteException{ System.out.println("Starting callbacks.");Iterator<CbClientInt> i = clients.iterator( );while (i.hasNext()) {

CbClientInt client = i.next();client.notifyMe(name); }

System.out.println("Callbacks complete."); } }

Page 389: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 14Andrea Corradini

L'ATTIVAZIONE DEL SERVER

import java.rmi.server.*; import java.rmi.registry.*;

public class CbServer {

public static void main(String[ ] args) {try { /* registrazione presso il registry */

System.out.println("Binding CallbackHello");CbServerImpl server = new CbServerImpl( );String name = "CallbackHelloServer";Registry registry = LocateRegistry.getRegistry ("localhost",2048);registry.rebind (name, server);System.out.println("CallbackHello bound");

} catch (Exception e) { e.printStackTrace();System.exit(-1); } } }

Page 390: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 15Andrea Corradini

L'INTERFACCIA DEL CLIENT

import java.rmi.*;

public interface CbClientInt extends Remote {

/* Metodo invocato dal server per effettuare

una callback a un client remoto. */

public void notifyMe(String message) throws RemoteException;

}

notifyMe(...)

è il metodo esportato dal client e che viene utilizzato dal server per

la notifica di un nuovo contatto da parte di un qualsiasi client. Viene

notificato il nome del client che ha contattato il server.

Page 391: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 16Andrea Corradini

L'IMPLEMENTAZIONE DEL CLIENT

import java.rmi.*; import java.rmi.server.*;

public class CbClientImpl extends UnicastRemoteObject

implements CbClientInt {

/* crea un nuovo callback client */

public CbClientImpl( ) throws RemoteException { super( ); }

/* metodo che può essere richiamato dal servente */

public void notifyMe(String message) throws RemoteException {String returnMessage = "Call back received: " + message;System.out.println( returnMessage); } }

Page 392: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 17Andrea Corradini

ATTIVAZIONE DEL CLIENT

import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*;

public class CbClient {

public static void main(String args[ ]) {

try {System.out.println("Cerco CallbackHelloServer");Registry registry = LocateRegistry.getRegistry("localhost", 2048);String name = "CallbackHelloServer"; /* crea stub di oggetto remoto */CbServerInt h = (CbServerInt) registry.lookup(name);/* si registra per il callback */System.out.println("Registering for callback");CbClientImpl callbackObj = new CbClientImpl( );h.registerForCallback(callbackObj);

Page 393: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 18Andrea Corradini

ATTIVAZIONE DEL CLIENT

/* accesso al server - fa una serie casuale di 5-15 richieste */int n = (int) (Math.random( ) * 10 + 5);String nickname= "mynick";for (int i=0; i< n; i++) {

String message = h.sayHello(nickname);System.out.println( message);Thread.sleep(1500); }

/* cancella la registrazione per il callback */System.out.println("Unregistering for callback");h.unregisterForCallback(callbackObj);

} catch (Exception e) {

System.err.println("HelloClient exception: " +e.getMessage( ));

e.printStackTrace(); System.exit(-1); }}}

Page 394: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 19Andrea Corradini

RMI:ECCEZIONI

Eccezione che viene sollevata se non trova un servizio di registry su quella porta. Esempio:

HelloClient exception: Connection refused to host: 192.168.2.103; nested exception is: java.net.ConnectException: Connection refused: connect

Eccezione sollevata se si tenta di registrare più volte lo stesso stub con lo stesso nome nello stesso registry

Esempio

CallbackHelloServer exception: java.rmi.AlreadyBoundException: CallbackHelloServer java.rmi.AlreadyBoundException: CallbackHelloServer

Page 395: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 20Andrea Corradini

ESERCIZIO 1: ELEZIONI CON CALLBACK

La scorsa lezione precedente è stato assegnato un esercizio per la

gestione elettronica di una elezione a cui partecipano un numero

prefissato di candidati. Si chiedeva di realizzare un server RMI che

consentisse al client di votare un candidato e di richiedere il numero di

voti ottenuti dai candidati fino ad un certo punto.

Modificare l’esercizio in modo che il server notifichi ogni nuovo voto

ricevuto a tutti i clients che hanno votato fino a quel momento. La

registrazione dei clients sul server avviene nel momento del voto.

Page 396: Java - Programmazione di Reti

Lezione 10: RMI CallBacks - Miscellanea 21Andrea Corradini

ESERCIZIO 2: GESTIONE FORUM Si vuole implementare un sistema che implementi un servizio per la gestione di forum in rete. Un forum è caratterizzato da un argomento su cui diversi utenti, iscritti al forum, possono scambiarsi opinioni via rete.

Il sistema deve prevedere un server RMI che fornisca le seguenti funzionalità:

a) apertura di un nuovo forum, di cui è specificato l'argomento (esempio: giardinaggio)

b) registrazione ad un forum, di cui è specificato l'argomento

c) inserimento di un nuovo messaggio indirizzato ad un forum identificato dall'argomento (es: è tempo di piantare le viole, indirizzato al forum giardinaggio); il messaggio deve essere inviato agli utenti iscritti al forum

d) reperimento dell'ultimo messaggio inviato ad un forum di cui è specificato l'argomento.

Quindi il messaggio può essere richiesto esplicitamente dal client oppure può essere notificato ad un client precedentemente registrato.