===== Note (LPRb 2007--2008) ===== ==== Configurazione dell'ambiente Java ==== Al centro di calcolo esistono tre versioni di Java: la 1.4, la 1.5 e la 1.6. Per far sì che la versione utilizzata sia la 1.x, procedere come segue: * se usate bash, nel file .bashrc nella vostra home, inserite le due righe che seguono (alla fine del file): export PATH=/usr/local/java/...versionescelta.../bin\:$PATH export JAVA_HOME=/usr/local/java/...versionescelta.../bin * se usate tcsh, nel file .cshrc nella vostra home, inserite le due righe (come ultime righe del file): setenv PATH /usr/local/java/...versionescelta.../bin\:$PATH setenv JAVA_HOME /usr/local/java/...versionescelta.../bin Infine, da eclipse, nelle preferenze del progetto, cambiate il runtime settandolo (dopo averlo cercato con l’apposito bottone) all’ambiente che avete scelto. ==== Thread ==== Il capitolo sui Thread nella prima parte del libro di testo consigliato copre egregiamente l'argomento. Esiste un [[http://java.sun.com/docs/books/tutorial/essential/concurrency/|tutorial]] sulla concorrenza in Java che copre anche l'argomento dei thread sul sito della Sun. Infine, {{lpr-b:bignamithread.pdf|questa}} è una nota che riassume in forma molto compatta tutte le cose sui thread discusse a lezione. ==== Generics ==== I generics (terminologia Java per indicare i template C++) sono ormai standard nelle versioni di Java successive alla 1.4. Li useremo abbondamentemente durante il corso. Potete trovare un buon tutorial sul sito della Sun a questo [[http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf|indirizzo]] (è un file PDF). ==== Socket TCP/IP ==== L'utilizzo classico di **Socket** e **ServerSocket** è illustrato nel breve [[http://java.sun.com/docs/books/tutorial/networking/sockets/index.html|tutorial sul sito Sun]] ==== Programmino per testare ritorno carrello ==== Questo [[testRitornoCarrello|programma]] fa vedere come testare la lettura di un ritorno carrello su un *InputStreamReader*. ==== Tutorial su util.concurrent ==== Questo è il [[http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html|tutorial]] Sun sulla classe **java.util.concurrent** ==== Nota sull'apertura di ObjectInput/OutputStream ==== Quando si utilizzano ObjectStream (in Input e in Output) è necessario che le aperture avvengano nell'ordine giusto. Se sul server si apre un **ObjectInputStream** con una **ObjectInputStream ois = new ObjectInputStream(sock.getInputStream())**, occorre che sul client si apra il corrispondente **ObjectOutputStream** //prima// dell'apertura dell'**ObjectInputStream** che implementerà la comunicazione bidirezionale. Se non fosse così, le chiamate **new ObjectInputStream(sock.getInputStream())** su client //e// server si bloccherebbero. Quindi, la sequenza giusta di azioni fra client e server è una cosa tipo: SERVER CLIENT ... ... ServerSocket ss = ... Socket s = ... Socket s = ss.accept(); ObjectInputStream ois = new ObjectInputStream(s.getInputStream()); ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); // leggi la richiesta // scrivi la richiesta Req r = (Req) ois.readObject(); oos.writeObject(ric); ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); ObjectInputStream ois = new ObjectInputStream(s.getInputStream()); ... ... ==== Programmino ProtocolTester con URL ==== Questo è il [[codiceProtocolTesterUrl|codice]] per il protocol tester presentato e discusso nella lezione del 26/10. ==== Comando per controllare lo stato dei socket ==== Se state utilizzando socket su una macchina (Linux) potete utilizzare il comando **netstat** per vedere in quale stato si trovino (stato del protocollo TCP, come visto a lezione di reti). Il comando **netstat -p tcp** fa vedere tutti i dati relativi ai socket TCP sulla macchina. Per esempio: [dhcp-ospiti3:~/DownloadFolder/Anastasio/remoteserver] marcod% netstat -p tcp Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 dhcp-ospiti3.cli.65023 hu-in-f99.google.http CLOSE_WAIT tcp4 0 0 dhcp-ospiti3.cli.64137 mailserver.di.un.imap ESTABLISHED tcp4 0 0 dhcp-ospiti3.cli.63820 fujih3.cli.di.un.ssh ESTABLISHED tcp4 0 0 dhcp-ospiti3.cli.63596 mailserver.di.un.imap ESTABLISHED tcp4 0 0 dhcp-ospiti3.cli.60752 mailserver.di.un.imap ESTABLISHED tcp4 0 0 dhcp-ospiti3.cli.60732 pacifico.di.unip.ssh ESTABLISHED tcp4 0 0 localhost.netinfo-loca localhost.986 ESTABLISHED tcp4 0 0 localhost.986 localhost.netinfo-loca ESTABLISHED tcp4 0 0 localhost.netinfo-loca localhost.1021 ESTABLISHED tcp4 0 0 localhost.1021 localhost.netinfo-loca ESTABLISHED [dhcp-ospiti3:~/DownloadFolder/Anastasio/remoteserver] marcod% fa vedere le connessioni aperte sulla mia macchina, per esempio una connessione fra la port 60732 e la porta ssh (23) di pacifico. Se per esempio state utilizzando un server che pubblica un socket sulla porta 54321, con il comando **nestat -p tcp | grep 54321** potete osservarne lo stato: [dhcp-ospiti3:~/DownloadFolder/Anastasio/remoteserver] marcod% netstat -a | grep 54321 tcp46 0 0 *.54321 *.* LISTEN [dhcp-ospiti3:~/DownloadFolder/Anastasio/remoteserver] marcod% Notare che il socket è marcato come **tcp46**, ovvero che può lavorare sia con TCP/IPv4 che con TCP/IPv6. Dipenderà dalla connessione se si utilizzarà un protocollo o l'altro. Se lo stato fosse **CLOSE_WAIT** (come nella prima riga dell'uscita del primo comando) siete nella condizione in cui il socket è stato chiuso e non si può ancora riutilizzare l'indirizzo perchè si attende il timeout che escluderà che pacchetti diretti a questo socket siano intercettati da un nuovo socket aperto sulla stessa porta. Per esempio, dopo aver lanciato un client che si connette alla 54321, e dopo che il client sia terminato, otterremo: Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 localhost.54321 localhost.65226 CLOSE_WAIT tcp46 0 0 *.54321 *.* LISTEN C'e' ancora la possibilità di connettersi alla 54321 (che è listening) mentre la connessione precedente (che aveva avuto come porta effimera del client la 65226) è in CLOSE_WAIT. Si veda la documentazione completa di nestat con **man netstat**. ==== Classe ODP (Object Datagram Packet) ==== Questo è il [[sorgenteODP|sorgente]] della classe ODP, discussa a lezione, che si può utilizzare per l'invio e la ricezione di Object mediante DatagramPacket. La classe è stata modificata rispetto a quanto presentato a lezione, in verità, perchè è stato aggiunto il controllo sulla dimensione del pacchetto. I metodi sono stati trasformati in modo dal lanciare eccezzioni in caso di problemi. Verificatene l'utilizzabilità e modificatela pure a vostro piacimento. ==== DatagramSocket che perde una percentuale di pacchetti ==== Se volete testare programmi che utilizzano DatagramSocket per la spedizione di pacchetti UDP utilizzate [[lpr-b:datagrampacket|questa implementazione]]. Vedi anche pagina degli [[lpr-b:esercizi#test_datagram|esercizi]]. L'implementazione perde una percentuale di pacchetti stabilita dall'utente (il 10% per default). ==== Documentazione su RMI ==== Esiste un {{http://java.sun.com/docs/books/tutorial/rmi/overview.html|tutorial}} sul sito Sun/Java che spiega esaudientemente tutto quanto serve per realizzare programmi Java con RMI. Un altro mini tutorial decente si trova su {{http://www.javacoffeebreak.com/articles/javarmi/javarmi.html|javacoffebreak}}. Informazioni dettagliate sull'uso delle policy si trovano anche su {{http://www.exampledepot.com/egs/java.security/UsePolicy.html|The Java Developers Almanac}} (anche se queste fanno ancora riferimento a versioni vecchie di Java). ==== Security Managers con RMI ==== Quando si voglia (o si debba) usare un SecurityManager per permettere caricamento dinamico di classi con RMI, si deve specificare un file con i permessi necessari alla polocy che si vuole implementare secondo il formato standard definito da Java ({{http://java.sun.com/j2se/1.4.2/docs/guide/security/PolicyFiles.html|pagina sito Sun/Java}}). In questo caso, il programma deve essere lanciato definendo a riga di comando quale file di policy deve essere consultato. A tale scopo si usa la sintassi java -Djava.security.policy=FileCheContieneLaPolicy nomeDellaClasseMain Da notare che apparentemente una grant { permission java.security.AllPermissions; }; non da' i permessi necessari alla lookup dell'oggetto remoto che vanno pertanto specificati con una permission esplicita tipo: permission java.net.SocketPermission "fujih1.cli.di.unipi.it", "connect,resolve"; dove il nome della macchina può essere sostituito dal wildcard "*" ==== Esempio commentato sull'uso delle callback con RMI ==== Su {{http://www.itec.uni-klu.ac.at/~harald/ds2001/rmi/pattern/pattern2.html|questo link}} trovate un esempio di codice master/worker realizzato con RMI sia senza che con le callback.