Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.
lpr-b-2007-2008:esercizi [28/11/2007 alle 08:12 (17 anni fa)] Marco Danelutto |
lpr-b-2007-2008:esercizi [19/09/2008 alle 14:08 (16 anni fa)] |
||
---|---|---|---|
Linea 1: | Linea 1: | ||
- | ===== LPRb 2007--2008: Esercizi assegnati a lezione ===== | ||
- | [[lpr-b: | ||
- | |||
- | ==== Test di ingresso ==== | ||
- | * Si realizzi un programma Java che si comporta come il comando Unix cat (il programma deve copiare quanto letto dallo standard input sullo standard output) //da completare in 10 minuti// | ||
- | * Si realizzi un programma che stampa i metodi statici di una classe. Il nome della classe è passato come parametro della riga di comando // da completare in 15 minuti // | ||
- | * Si realizzi un programma nel quale due thread si alternano in esecuzione: il primo thread attende un numero di secondi random, compreso fra 0 e 10, poi si sospende, mandando in esecuzione il secondo thread. Il secondo thread attende un numero di secondi random, sempre compreso fra 0 e 10, quindi si sospende riattivando il primo thread, e così via. Durante il periodo di attesa, i thread stampano un messaggio con il proprio identificatore ogni secondo. // da completare in 20 minuti // | ||
- | === Soluzione === | ||
- | * comando [[cat|Cat]] | ||
- | * [[metodiStatici|metodi statici]] di una classe | ||
- | * thread che si alternano in esecuzione: [[alternatingProtocol|oggetto condiviso]], | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== Pool di Thread ==== | ||
- | Si realizzi un programma in grado di eseguire calcoli generici utilizzando un pool di thread. I calcoli da eseguire sono quelli modellati dal metodo **compute** definito dall' | ||
- | <code java> | ||
- | public interface Compute< | ||
- | public S compute(T x); | ||
- | } | ||
- | </ | ||
- | i valori di tipo *T* da calcolare si devono prelevare da un **Repository< | ||
- | |||
- | {{ lpr-b: | ||
- | |||
- | La classe **Repository< | ||
- | <code java> | ||
- | ... modificatori opportuni ... void insert(T x) // inserisce un oggetto di tipo T nel repository | ||
- | ... modificatori opportuni ... T extract() | ||
- | </ | ||
- | Per l' | ||
- | Per il generatore, si può usare la classe: | ||
- | <code java> | ||
- | public class Generatore extends Thread { | ||
- | |||
- | Repository< | ||
- | int n = 10; | ||
- | final int DELAY = 1000; | ||
- | final float RANGE = (float) 1024.00; | ||
- | |||
- | /** | ||
- | * costruttore | ||
- | * @param n numero di oggetti da generare | ||
- | * @param rep repository nel quale depositare gli oggetti generati | ||
- | */ | ||
- | public Generatore(int n, Repository< | ||
- | this.rep = rep; | ||
- | this.n = n; | ||
- | } | ||
- | |||
- | /** | ||
- | * corpo del thread generatore: ciclo finito che genera interi compresi fra 0 e RANGE | ||
- | */ | ||
- | public void run() { | ||
- | for(int i=0; i<n; i++) { | ||
- | try { | ||
- | rep.insert(new Integer((int) (Math.random() * RANGE))); | ||
- | sleep(DELAY); | ||
- | } catch(InterruptedException e) { | ||
- | System.out.println(" | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | } | ||
- | </ | ||
- | Per lo stampatore invece, si consideri il codice | ||
- | <code java> | ||
- | public class Stampatore< | ||
- | |||
- | Repository< | ||
- | |||
- | public Stampatore(Repository< | ||
- | this.rep = rep; | ||
- | } | ||
- | |||
- | public void run() { | ||
- | while(true) { | ||
- | T i = rep.extract(); | ||
- | System.out.println(" | ||
- | } | ||
- | } | ||
- | } | ||
- | </ | ||
- | Durante l' | ||
- | Si può realizzare il programma senza necessariamente trattare la terminazione. Una volta realizzato il programma, si rimuova il ritardo nel ciclo di produzione dei valori iniziali da parte del **Generatore** e si inserisca, nel thread **Calcolatore** un ritardo pseudo casuale fra 0 e 5 secondi, utilizzando il codice: | ||
- | <code java> | ||
- | try { | ||
- | int random = ((int)(Math.random() * 5000.00)) | ||
- | System.out.println(" | ||
- | sleep(random); | ||
- | ... calcolo vero e proprio ... | ||
- | System.out.println(" | ||
- | } catch(...) {...} | ||
- | </ | ||
- | Si controlli quindi che i meccanismi di sincronizzazione fra thread funzionano ancora e che effettivamente si siano più thread che calcolano contemporaneamente. | ||
- | |||
- | === Soluzione === | ||
- | == Senza terminazione == | ||
- | * Codice per l' | ||
- | * Codice per la classe [[ThreadComputeCalcolatore|ThreadComputer]] che implementa il singolo thread del ThreadPool (Calcolatore, | ||
- | * Codice del [[ThreadPoolRepository|Repository]] | ||
- | == Soluzione con terminazione == | ||
- | * Codice per il [[RepositoryTermina|repository]]: | ||
- | * Codice del [[ThreadTermina|thread calcolatore]] e codice del [[maintermina|main]]. Il thread calcolatore termina se gli arriva un' | ||
- | * Codice dello [[StampatoreTermina|stampatore]] che termina. Si rileva l' | ||
- | |||
- | == Soluzione che usa java.util.concurrent == | ||
- | Prima versione: utilizza un thread pool di java.util.concurrent ma usa ancora i Repository come precedentemete definiti: | ||
- | * Codice con il [[mainTPconcurr|main]] di prova | ||
- | * Codice per il calcolo del singolo [[taskTPconcurr|task]] | ||
- | * tutto il resto del codice è uguale a quello delle soluzioni precedenti | ||
- | Seconda versione: utilizza una LinkedBlockingQueue per realizzare i Repository: | ||
- | * Codice per il [[mainTPconcurDue|main]] | ||
- | * Codice per lo [[stampatoreTPconcurDue|Stampatore]] (cambia il metodo chiamato per l' | ||
- | * Codice per il [[taskDueC|task]] (cambia il costruttore) | ||
- | * tutto il resto del codice è identico | ||
- | |||
- | ==== Server di upload file ==== | ||
- | Utilizzando socket TCP/IP, si realizzi un server che mette a disposizione un servizio di file upload. Il client che intende fruire del servizio si connette ed invia: | ||
- | - il nome del file di cui si vuole fare l' | ||
- | - un ritorno carrello (è la stringa " | ||
- | - l' | ||
- | Il server, a seguito dell' | ||
- | |||
- | Dunque sulla macchina fujih3 potremmo lanciare il comando | ||
- | |||
- | java serverUpload.Server /tmp | ||
- | |||
- | (primo ed unico parametro è la directory di upload) mentre sulla macchina fujih5 potremmo lanciare il comando | ||
- | |||
- | java serverUpload.Client fujih3 prova.txt | ||
- | |||
- | (il primo parametro è il nome dell' | ||
- | |||
- | Si realizzi il Server prima come server single thread e successivamente come server multithreaded. In entrambi i casi, il Server deve essere in grado di eseguire l' | ||
- | |||
- | == Soluzione proposta == | ||
- | * [[clientUpload|Client]] e [[serverUpload|server]] che fanno uso solo di InputStream e OutputStream per implementare la comunicazione su socket. | ||
- | * [[serverUploadBuffered|Server]] che utilizza un **BufferedReader** per la comunicazione sul socket (il client è lo stesso). | ||
- | |||
- | |||
- | |||
- | |||
- | ==== Instant messanger ==== | ||
- | Si realizzi un programma che implementa un instant messanger punto a punto. Lanciando il programma su due macchine diverse e passando il nome dell' | ||
- | |||
- | I due programmi lanciati sulle due macchine devono essere identici. | ||
- | |||
- | Qualora si tenti un contatto su una macchina dove ancora non è stata avviato il programma per l' | ||
- | |||
- | {{ lpr-b: | ||
- | |||
- | == Soluzione proposta == | ||
- | * Codice per il [[messangerMain|Messanger]] | ||
- | * Codice per il [[copyThreadMessanger|CopyThread]] | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== NsLookup con cache ==== | ||
- | |||
- | Si realizzi un server multithreaded che accetta richieste di risoluzione di nomi di host. La risoluzione dei nomi deve prevedere l' | ||
- | {{ lpr-b: | ||
- | Il client deve stampare un messaggio con il numero di millisecondi necessari ad ottenere la risposta. A tale scopo si utilizzi il metodo statico **currentTimeMillis()** della classe **System** che restituisce il "tempo di sistema" | ||
- | |||
- | |||
- | == Soluzione proposta == | ||
- | * File [[namequery|NameQuery.java]] | ||
- | * File [[nameserver|NameServer.java]] | ||
- | * File [[nslookup|NsLookup.java]] | ||
- | * File [[QueryAnswer|QueryAnswer.java]] | ||
- | * File [[ServerThread|ServerThread.java]] | ||
- | |||
- | |||
- | ==== Trasferimento file (TFTP con UDP) ==== | ||
- | |||
- | Si vuole realizzare una coppia di programmi che permettano di trasferire l’intero contenuto di un file da una macchina all’altra, | ||
- | |||
- | Si dovranno quindi realizzare due programmi: un Sender che prende come parametri il file da trasmettere, | ||
- | |||
- | Si supponga che il pacchetto da trasmettere sia modellato dalla classe [[TFTmessageClass|TFTmessage]] | ||
- | La classe TFTPmessage prevede sia un numero di sequenza che una marca booleana che dice se devono essere spediti ancora pacchetti del file oppure se la spedizione è terminata. Tali campi vanno utilizzati per gestire le ritrasmissioni in modo corretto, sia dal lato Sender (ritrasmissione di pacchetti con dati relativi al file) sia lato Receiver (ritrasmissione dei pacchetti di tipo ACK). | ||
- | Utilizzando ODP, si può spedire un oggetto in un DatagramPacket creando un ODP col costruttore che prende come parametro l’oggetto da spedire e successivamente invocando sull’oggetto creato un metodo getDatagramPacket. Per ricevere un oggetto serializzato in un DatagramPacket, | ||
- | |||
- | == Soluzione proposta == | ||
- | * File [[ODP|ODP.java]] | ||
- | * File [[Sender|Sender.java]] | ||
- | * File [[Receiver|Receiver.java]] | ||
- | * File [[TFTPmessage|TFTPmessage.java]] | ||
- | |||
- | =============================== | ||
- | |||
- | |||
- | |||
- | |||
- | ==== Server NFS ==== | ||
- | |||
- | Si realizzi un semplice server NFS, utilizzando esclusivamente il protocollo UDP. Il server deve accettare richieste di apertura, lettura, scrittura e chiusura di file. L' | ||
- | * un handle (che il server dovra' cachare) per le successive operazioni (di tipo String, per esempio) in caso di open | ||
- | * un byte[] contenente l' | ||
- | * un errore o un codice di successo nel caso di close e di write. | ||
- | In particolare, | ||
- | * OPEN \n filename \n per la richiesta di apertura di un file | ||
- | * READ \n handle \n nbytedaleggere \n per la richiesta di lettura di un file con handler dato | ||
- | * CLOSE \n handle \n per la richiesta di chiusura di un file con handler dato | ||
- | * WRITE \n handle \n seguito da un byte[] opportunamente codificato contenente i byte da scrivere per la richiesta di scrittura di un file con handler dato | ||
- | * ERROR \n argomenti dell' | ||
- | * OK \n per i messaggi di successo | ||
- | * HANDLE \n handle \n per le risposte ai messaggi di apertura avvenuta con successo. | ||
- | |||
- | Vista la complessità | ||
- | * classe **RemoteInputStream**, | ||
- | * classe **RemoteOutputStream**, | ||
- | * classe **UDPServerComm**, | ||
- | * class **NfsServer**, | ||
- | Le prime due classi dovrebbero permettere di scrivere un cliente tipo: | ||
- | < | ||
- | | ||
- | | ||
- | | ||
- | byte [] buffer = ris.read(100); | ||
- | | ||
- | | ||
- | } | ||
- | |||
- | </ | ||
- | per leggere parte del file che si trova su fujih1 se sul fujih1 sta girando un NfsServer. | ||
- | |||
- | |||
- | === Soluzione === | ||
- | * classe [[ilserver|NfsServer.java]] | ||
- | * classe [[remotestream|RemoteStream.java]] | ||
- | * classe [[remoteinputstream|RemoteInputStream.java]] | ||
- | * classe [[remoteoutputstream|RemoteOutputStream.java]] | ||
- | * classe [[streamref|StreamRef.java]] | ||
- | * classe [[remotepacket|RemotePacket.java]] | ||
- | * classe [[udpservercomm|UDPServerComm.java]] | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== Chat con multicast ==== | ||
- | Si realizzi un client chat che permetta la comunicazione di semplici messaggi di testo fra più utenti. Il programma deve fare uso di multicast UDP. | ||
- | La chat avviene utilizzando un indirizzo di multicast passato come parametro della riga di comando. I messaggi inviati alla chat dal singolo utente vengono semplicemente inviati al gruppo di multicast. Tutti i messaggi diretti all' | ||
- | |||
- | Successivamente si modifichi il programma in modo da utilizzare broadcast invece che multicast per l' | ||
- | |||
- | Si faccia in modo che i messaggi stampati a video comincino sempre con l' | ||
- | |||
- | fujih4: | ||
- | ciao | ||
- | From / | ||
- | Come va | ||
- | From / | ||
- | From / | ||
- | |||
- | === Soluzione proposta === | ||
- | |||
- | * [[copyin|thread copiatore (pacchetti -> video)]] | ||
- | * [[copyout|thread copiatore (tastiera -> pacchetto)]] | ||
- | * [[mainchat|main]] | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ==== Test Datagram ==== | ||
- | Questo non è un esercizio vero e proprio. E' la realizzazione di una classe che sottoclassa DatagramSocket e implementa un metodo send che " | ||
- | Utilizzando questa classe invece della DatagramSocket standard si può facilmente verificare il funzionamento di un software che utilizza protocolli basati su UDP. | ||
- | |||
- | * codice della classe [[datagrampacket|DatagramPacket]] | ||
- | | ||
- | |||
- | ==== ContoCorrente RMI ==== | ||
- | Si realizzi un oggetto ContoCorrente e lo si renda accessibile da remoto utilizzando la tecnologia RMI, che permetta di effettuare operazioni di | ||
- | | ||
- | long saldo() | ||
- | long prelievo(long cifra) | ||
- | long deposito(long cifra) | ||
- | String ultimiMovimenti(int n) // restituisce gli ultimi n movimenti, uno per riga | ||
- | |||
- | Si realizzino: | ||
- | * un' | ||
- | * l' | ||
- | * un main che crea il registry e pubblica l' | ||
- | * un cliente che accetta come parametri dalla riga di comando il nome dell' | ||
- | |||
- | Si faccia in modo che ciascuna delle operazioni dell' | ||
- | |||
- | | ||
- | [[lpr-b: |