Lab. di programmazione di rete - b
 
Esercizi
Accept: */*
Accept-Language: en
Accept-Encoding: gzip, deflate
Cookie: monster_728x240_expAnsa_091006=00238b6afa1ff3e8e1393f86619f6837;
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Safari/419.3
Pragma: no-cache
Connection: keep-alive
Proxy-Connection: keep-alive
 

-- fine pacchetto
 
Dove le ultime due righe corrispondono alle due coppie "\r\n" previste dal protocollo HTTP come "chiusura" di un pacchetto (il protocollo HTTP è un protocollo ASCII!).
 
    /**
     * utilizzata per prelevare dal conto
     * @param somma la somma da prelevare
     * @return  la somma prelevata
     */
    public int prelievo(int somma);
    /**
     * utilizzata per richiedere il saldo
     * @return la cifra del saldo
     */
    public int saldo();
    /**
     * utilizzata per effettuare un versamento
     * @param somma la somma da versare
     * @return la cifra del saldo a versamento avvenuto
     */
    public int versamento(int somma);
    }

Il server deve accettare richieste di saldo, versamento e prelievo su un socket pubblicato sulla porta 25252. Le richieste dovanno avvenire secondo un protocollo  di tipo ASCII che prevede i seguenti messaggi:

   RICHIESTA
    SALDO: numeroconto
   FINERICHIESTA

   RICHIESTA
    PRELIEVO: numeroconto cifra
   FINERICHIESTA

   RICHIESTA
    VERSAMENTO: numerconto cifra
    FINERICHIESTA

   RISPOSTA
   OPT CIFRA: risultato
    FINERISPOSTA
 
    RISPOSTA
   ERRORE: messaggiodierrore
    FINERISPOSTA
 
Il cliente spedisce un messaggio di tipo richiesta e, sulla stessa connessione, riceve un messaggio di risposta, ad operazione avvenuta. Il server chiude la connessione appena inviata la risposta.

Si realizzino due versioni del server, una single threaded a una multithreaded e si dimostri che entrambe le versioni impediscono il prelievo “concorrente” di somme maggiori al saldo del conto stesso.
 
Soluzione proposta: codice dell’interfaccia BancomatInterface, della classe ContoCorrente, del Client, del server (single threaded e multithreaded) e del thread utilizzato nel server (chiamato come oggetto normale (method run) nella versione single threaded e come thread vero e proprio (methodo start) nella versione multithreaded). (tar file con tutti i sorgenti compressi)
 
  1. 10. Discovery UDP

    Vogliamo fare in modo che un host possa dinamicamente scoprire quali altri host sono presenti sulla sua sottorete disposti a partecipare ad una certa applicazione. In particolare vogliamo fare in modo che un host possa “dichiarare” la propria presenza che un altro host possa stilare un elenco di tutti gli host che si sono dichiarati presenti. A tale scopo, si realizzino una coppia di programmi:
  2.     il primo attende un messaggio in  multicast su una certa porta (un messaggio di discovery) e replica con un messaggio di “presenza”. Il messaggio di discovery viene atteso su un indirizzo di multicast (cioè dopo aver fatto una joinGroup) ma il messaggio di risposta (di presenza) deve essere spedito in unicast all’host che ha inviato il messaggio di discovery.
  3.     il secondo  invia periodicamente dei messaggi di discovery e  mantiene un elenco aggiornato degli host che rispondono con il messaggio di presenza.
Il primo programma andra' mandato in esecuzione sugli host che vogliono partecipare al protocollo, mentre il secondo dovra' essere mandato in esecuzione solo sull'host che vuole scoprire quali host siano presenti nella rete disposti a partecipare al protocollo.
Si prenda in considerazione che:
  1.     i messaggi in multicast UDP sono inaffidabili. Di conseguenza si faccia in modo che l'annuncio di discovery venga effettuato periodicamente (ogni dieci secondi, per esempio), ma si faccia anche in modo che i messaggi di risposta inviati in conseguenza della ricezione del messaggio di discovery vengano ripetuti un certo numero di volte (per esempio 3 volte) a distanza di 3 secondi l’uno dall’altro.
  2.     dato che i messaggi vengono ripetuti, si deve evitare la registrazione di host piu' di una volta
  3.     sia l'attivita' di registrazione che quella di annuncio dovrebbero essere attivita' concorrenti rispetto all'attivita' principale dei programmi, e quindi andrebbero programmate utilizzando appositi thread.
Per questo protocollo si assuma che il messaggio di  discovery abbia la forma (ASCII)

    DISCOVERY nomeHostMittente

e che il messaggio di presenza abbia la forma

    PRESENCE nomeHostPresente

Per l’indirizzo di multicast utilizzate l’indirizzo di multicast 232.131.11.xxx dove xxx rappresenta il risultato del modulo fra la vostra matricola e 253 + 1, questo per cercare di  evitare conflitti in aula.  
 
Soluzione proposta: jar file dei sorgenti
 
  1. 11.    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, utilizzando un protocollo tipo TFTP implementatao su datagram socket. Il protocollo TFTP prevede la trasmissione dell’intero file mediante la sepdizione di un certo numero di pacchetti, ognuno dei quali contiene una parte del file. La spedizione di un messaggio (tranne che nel caso del primo messaggio) può avvenire solo dopo la ricezione di un ACK da parte del destinatario. In caso non venga ricevuto l’ACK entro un certo timeout (per esempio entro due secondi) il mittente deve provvedere alla ritrasmissione del pacchetto. Analogamente, il destinatario che non veda arrivare un pacchetto entro un certo timeout deve provvedere alla rispedizione dell’ultimo ACK, nell’eventualità che si sia perso.
Si dovranno quindi realizzare due programmi:  un Sender che prende come parametri  il fiel da trasmettere, l’host destinazione e la porta destinazione e trasmette il file, e un Receiver che prende come parametri il nome del file da scrivere e la porta da utilizzare e riceve il file salvandolo su disco.  Per verificare che i due programmi funzionino correttamente, lanciare una shell remota su una macchina diversa da quella su cui state lavorando, poi lanciate il Sender su una macchina e il Receiver sull’altra macchina, date due nomi di file diversi e alla fine eseguite un comando diff filename1 filename2. Se ritorna il prompt della shell senza messaggi vuol dire che i file sono uguali, altrimenti c’e’ stato un errore. Provate a trasferire sia file di tipo testo che file di tipo binario  (per esempio, file .class)).
Si supponga che il pacchetto da trasmettere sia modellato dalla classe TFTmessage e che questi oggetti siano serializzati innetro ai DatagramPacket utilizzando la classe ODP già vista a lezione quando abbiamo introdotto la serializzazione degli oggetti.
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, si usa il metodo statico getODP per ottenere un ODP dal DatagramPacket e successivamnete una getObject sull’oggetto ODP restituito dalla getODP per ottenre l’oggetto deserializzato.
 
Soluzione proposta: jar file dei sorgenti, UnreliableNetwork.DatagramSocket (questa classe si può usare al posto dei normali DatagramSocket qualora si voglia verificare cosa succede in caso di problemi con la trasmissione dei datagram UDP. I DatagramSocket forniti da questa classe, perdono per defulat il 10% dei pacchetti spediti, indipendentemente dalla caratteristiche della rete a disposizione. La perdita dei pacchetti è simulatoa utilizzando uno dei generatori pseudocasuali dell’ambiente Java)
 
  1. 12.    Gestione calendario orali mediante RMI
Si implementi un oggetto RMI che permette la registrazione di uno studente per la discussione del progetto di LPRb. L’oggetto deve mettere a disposizione i metodi dell’interfaccia che segue:
 
public interface RegistrazioneDiscussione {
 
    /**
     * Tenta di effettuare una registrazione. La registrazione pu˜ fallire perche' per quel
     * giorno non vi sono piu' posti disponibili
     * @param matricola matricola della persona da registrare
     * @param nome nome della persona da registrare
     * @param giorno il giorno scelto per la discussione
     * @return true se la registrazione  avvenuta con successo, false se non c'era
     * piu' posto per il giorno richiesto
     */
    public boolean registrazione(int matricola, String nome, int giorno)
            throws RemoteException;
 
    /**
     * utilizzata per "vedere" la lista delle registrazioni gia' attive per tutto il
     * periodo delle discussioni
     * @return la stringa con tutte le registrazioni
     * @throws RemoteException
     */
    public String  listaRegistrazioni() throws RemoteException;
 
    /**
     * utilizzata dal docente per inizializzare le disponibilita' nei vari
     * giorni previsti per la discussione
     * @parm passwd la password che permette l'accesso in modo "docente".
     * Viene confrontata con una passwd definita (compilata)
     * come costante nel codice dell'oggetto remoto. <br> Per esempio, se
     * i giorni utilizzabili per le discussioni fossero il 19, 20 e 21
     * e per ciascun giorno vi fosse disponibilita' per effettuare 8
     * discussioni, tranne che per il 20, quando la disponibilita' fosse solo
     * per 4 discussioni, si effettuerebbe una chiamata:
     * <code>oggettoRemoto,assegnaPosti("passwd",{19,20,21},{8,4,8});</code>.
     * @param giorni vettore dei giorni utilizzabili per la discussione
     * @param disponibilita disponibilita' per il giorno con lo stesso indice
         nel vettore dei giorni
     * @throws RemoteException
     */
    public void    assegnaPosti(String passwd, int[]giorni, int[]disponibilita)
               throws RemoteException;
    
}
 
Si implementi un client che permette di effetture la registrazione, fornendo i dati necessari come parametri della riga di comando, ed un secondo client che permttea la visualizzazione della lista degli iscritti, nell’ordine in cui sono state effettuate le registrazioni ed un cliente che permetta di inzializzare la lista delle disponibilita’ da parte del docente.
In prima approssimazione, si utilizzino le stringhe per realizzare la passwd. Successivamente, si consideri la possibilità di evitare che la passwd viaggi in chiaro. Esiste un comando Linux (mkpasswd) che permette di ottenere la versione cifrata della passwd:
    mkpasswd --salt=”ci” ciccio
restituisce
    fujih1:~> mkpasswd --salt="ci" ciccio
    cia0donGk9pVk
    fujih1:~>
Avendo cura di passare come “salt” i primi due caratteri della passwd, questo comando resitutisce la passwd cifrata come di fatto viene memorizzata nel sistema. Si utilizzi quindi questo comando (dal client Java) per far si’ che la passwd non viaggi in chiaro nei parametri della chiamata al metodo “assegnaPosti”. Si utilizzi quindi un “Process” come quelli resituiti dal metodo exec degli oggetti Runtime. In altre parole, si utilizzi un
   Runtime rt = Runtime.getRuntime();
per ottenere un runtime, sul qule successivamente si crea un processo con una
   Process p = rt.exec(“mkpasswd --salt=\”ci\” ciccio”);
L’output del processo può essere acceduto mediante l’InputStream ottenuto con uan
   p.getInoutStream();
in maniera del tutto analoga a quello che avviene con i Socket.
 
Soluzione proposta: Codice dell’interfaccia, dell’oggetto  e del server remoto e codice del cliente.
 
  1. 13.    Codice commentato
Questo non è un esercizio di quelli assegnati a lezione, bensì costituisce una raccolta di esempi di codice utili per la comprensione di alcuni aspetti fra quelli illustrati durante il corso.
  1.     Codice che illustra l’esecuzione di un comando mediante RunTime e Process
  2.     Codice che illustra l’implementazione di una killall (sempre con RunTime e Process)
  3.     Codice (sorgenti in un JAR file) dell’esempio commentato a lezione per RMI
  4.     Codice  della classe che illustra come caricare dinamicamente una classe ed instanziarne un oggetto