Materiale addizionale per esercitazioni facoltative Socket Java con connessione Server Sequenziale Std Input Sviluppare un applicazione C/S che effettui il trasferimento di un file dal client al server (put) usando una connessione. In particolare nel servizio: nome file client put file rete put file server file il client chiede all utente il nome di un file da trasferire, si connette al server (con java.net.socket), crea uno stream di output sulla connessione attraverso cui inviare il file selezionato, preceduto dal suo nome. Se anziché il nome del file l utente inserisce un asterisco, il client invia al server tutti i file di testo contenuti nel direttorio corrente. Ogni file è preceduto dal nome del file stesso. il server attende una richiesta di connessione da parte del client (su java.net.serversocket), usa la socket (java.net.socket) prodotta dalla connessione per creare uno stream di input da cui riceve il nome del file e il file che stamperà poi a video, dopodiché chiude la connessione. In caso di invio ripetuto, la stessa connessione viene usata per tutti i file (nome e contenuto) fino al termine della connessione da parte del cliente Server Concorrente nome file2 client client client nome file1 put file2 nome file3 put file1 put file3 rete file1 serverthread1 put file1 serverthread3 Std Output file3 serverthread2 put file2 server put file3 file2 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 1 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 2
Filtraggi Filtro Input FILTRO Output Un filtro è un programma che consuma tutto il suo input e porta l uscita sull output Possiamo pensare di combinarne in una pipeline Esempi di creazione stream di input da socket: DataInputStream insock = new DataInputStream(socket.getInputStream()); Un filtro potrebbe leggere da uno stream fino alla fine del file e poi lanciare in output delle indicazioni Vedi la trasferisci_a_byte InputStreamReader isr = new InputStreamReader(socket.getInputStream()); BufferedReader in = new BufferedReader(isr); Esempi di creazione stream di output su socket: DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream()); BufferedWriter bw = new BufferedWriter(osw); PrintWriter out = new PrintWriter( bw, true); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 3 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 4
Schema di soluzione: il Client 1. Creazione socket ed eventuale settaggio opzioni: socket = new Socket( addr, PutFileServerSeq.PORT); socket.setxxx( ); 2. Interazione da console con l utente: BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Domanda "); String richiesta = stdin.readline(); 3. Creazione dello stream di output sulla socket: outsock = new DataOutputStream(socket.getOutputStream()); 4. Creazione dello stream di input da file: infile = new DataInputStream( new FileInputStream(nomeFile)); 5. Invio dei dati al server: outsock.writeutf(nomefile); FileUtility.trasferisci_a_byte (infile, outsock); 6. Chiusura della socket: socket.close(); Schema di soluzione: il Server 1. Creazione socket ed eventuale settaggio opzioni: serversocket = new ServerSocket(PORT); serversocket.setreuseaddress(true); 2. Attesa/accettazione di richiesta di connessione: clientsocket = serversocket.accept(); 3. Creazione dello stream di input sulla socket: insock = new DataInputStream( clientsocket.getinputstream()); 4. Ricezione dei dati dal client e invio dei dati sulla console in uscita nomefile=insock.readutf(); FileUtility.trasferisci_a_byte( insock, new DataOutputStream(System.out)); 5. Chiusura della connessione con il client: clientsocket.close(); 6. Chiusura della socket di ascolto: serversocket.close(); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 5 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 6
FileUtility public class FileUtility static protected void trasferisci_a_byte( DataInputStream src, DataOutputStream dest) throws IOException // ciclo di lettura da sorgente // e scrittura su destinazione byte buffer=0; int val=0; while ((buffer=src.readbyte())!= -1) dest.writebyte(buffer); catch(eofexception e) dest.writebyte(-1); dest.flush(); PutFile Client public class PutFileClient public static void main(string[] args) throws IOException InetAddress addr=null; Socket socket=null; DataInputStream infile=null; DataOutputStream outsock=null; // determinazione indirizzo server if (args.length == 0) addr = InetAddress.getByName(null); else addr = InetAddress.getByName(args[0]); catch(unknownhostexception e) System.exit(1); // creazione stream di input da tastiera BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); while (stdin.readline()!=null) // richiesta dati da utente System.out.print("Nome file (estensione)? "); nomefile = stdin.readline(); catch (Exception e) // se la richiesta è corretta creo socket e stream if (nomefile.equals("*") (new File(nomeFile)).exists()) // creazione socket try socket = new Socket( addr, PutFileServerSeq.PORT); socket.setsotimeout(30000); catch (Exception e) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 7 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 8
// creazione stream di output su socket outsock = new DataOutputStream(socket.getOutputStream()); catch(ioexception e) // se la richiesta non è corretta non proseguo else System.out.println("File non presente nel direttorio corrente"); /* la richiesta è corretta caso "*": invio di tutti i file.txt del direttorio corrente*/ if (nomefile.equals("*")) File f = new File("."); String[] listafile = f.list(); for (int i=0; i<listafile.length; i++) if (listafile[i].endswith(".txt")) // creazione stream di input da file infile = new DataInputStream( new FileInputStream(listaFile[i])); catch(filenotfoundexception e) outsock.writeutf(null); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 9 // trasmissione del nome outsock.writeutf(listafile[i]); catch(exception e) // trasmissione del file FileUtility.trasferisci_a_byte( infile, outsock); catch(exception e) // if.txt // for socket.close(); // if "*" /* caso di un nome specifico invio solo del file richiesto */ else // creazione stream di input da file infile = new DataInputStream( new FileInputStream(nomeFile)); catch(filenotfoundexception e) // trasmissione del nome outsock.writeutf(nomefile); catch(exception e) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 10
// trasmissione del file FileUtility.trasferisci_a_byte( infile, outsock); catch(exception e) socket.close(); // else // tutto ok, pronto per nuova richiesta System.out.print("\n^D(Unix)/^Z(Win)+invio per uscire, solo invio per continuare: "); // while /* qui catturo le eccezioni non gestite nel while: per esempio la chiusura della connessione con il server in seguito alle quali il client termina l'esecuzione */ catch(exception e) stdin.close(); socket.close(); PutFile Server Sequenziale public class PutFileServerSeq public static final int PORT = 1050; public static void main(string[] args) throws IOException ServerSocket serversocket = null; Socket clientsocket=null; DataInputStream insock=null; try serversocket = new ServerSocket(PORT); serversocket.setreuseaddress(true); catch(exception e) System.exit(1); while(true) System.out.println("\n In attesa di richieste..."); try clientsocket = serversocket.accept(); clientsocket.setsotimeout(30000); catch (Exception e) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 11 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 12
// creazione stream di input da socket insock = new DataInputStream( clientsocket.getinputstream()); catch(ioexception e) String nomefile; while (clientsocket.isconnected()) /* qui catturo le eccezioni non gestite all'interno del while in seguito alle quali il server termina l'esecuzione */ catch(exception e) // chiusura di stream e socket // SOLO IN CASO DI PROBLEMI clientsocket.close(); serversocket.close(); // ricezione del nome try nomefile=insock.readutf(); catch(exception e) break; //ciclo di ricezione dal client e scrittura su video FileUtility.trasferisci_a_byte( insock, new DataOutputStream(System.out)); catch(exception e) clientsocket.close(); break; clientsocket.close(); // while (true) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 13 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 14
PutFile Server Concorrente /* Thread lanciato per ogni richiesta accettata */ class ServerThread extends Thread private static int counter=0; private int id=++counter; private Socket socket; private DataInputStream insock=null; // costruttore public ServerThread(Socket s) throws Exception socket=s; try // creazione stream di input da socket insock = new DataInputStream(socket.getInputStream()); catch(ioexception e) throw e; /* se tutto ok il thread viene avviato direttamente dal costruttore */ if (insock!=null) start(); // costruttore public void run() try while (socket.isconnected()) String nomefile; // ricezione del nome. //ciclo di ricezione dal client e scrittura su video FileUtility.trasferisci_a_byte( insock, new DataOutputStream(System.out)); catch(exception e) socket.close(); break; // while (socket.isconnected()) socket.close(); catch(exception e) // run // ServerThread public class PutFileServerCon public static final int PORT = 1050; public static void main(string[] args) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 15 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 16
throws IOException ServerSocket serversocket = null; Socket clientsocket=null; serversocket = new ServerSocket(PORT); serversocket.setreuseaddress(true); catch(exception e) System.exit(1); while(true) System.out.println("Server: in attesa di richieste...\n"); try // bloccante finchè non arriva una // richiesta di connessione clientsocket = serversocket.accept(); clientsocket.setsotimeout(60000); catch (Exception e) e.getmessage()); // servizio delegato ad un nuovo thread new ServerThread(clientSocket); catch (Exception e) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 17 // while true /* qui catturo le eccezioni non gestite all'interno del while in seguito alle quali il server termina l'esecuzione */ catch(exception e) // chiusura di socket di accettazione serversocket.close(); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 18
Materiale addizionale per esercitazioni facoltative Socket Java senza connessione Client e Server Datagram Sviluppare un applicazione C/S in cui: il client invia al server pacchetti contenenti il nome del file e il numero della linea del file che vuole ricevere, che sono richiesti dall utente usando l input da console. Si stampa il contenuto del pacchetto ottenuto in risposta, che può essere la linea richiesta o una risposta negativa. Per evitare che, in caso di caduta del server o perdita di un pacchetto, il client si blocchi indefinitamente nell attesa della risposta è previsto un timeout di 30 s; client pkt2 pkt1 client rete server line2 line1 pkt3 pkt2 pkt1 line1 line2 line3 il server verifica l esistenza del file richiesto. Se il file non esiste notifica l errore, altrimenti tenta di estrarre la linea richiesta. Se la linea non esiste invia una notifica di errore. Altrimenti invia al client (o ai client) un pacchetto contenente la linea richiesta. Dopo 3 minuti senza ricezione di richieste il server termina. client pkt3 line3 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 19 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 20
La Classe DatagramPacket Classe con cui vengono rappresentati i pacchetti UDP da inviare e ricevere sulle socket di tipo Datagram. Si costruisce un datagram packet specificando: il contenuto del messaggio (i primi ilength bytes dell array ibuf) l indirizzo IP del destinatario il numero di porta su cui il destinatario è in ascolto public DatagramPacket(byte ibuf[], int ilength, InetAddress iaddr, int iport) Se il pacchetto deve essere ricevuto basta definire il contenuto: public DatagramPacket(byte ibuf[], int ilength) La classe mette a disposizione una serie di metodi per estrarre o settare le informazioni: getaddress(), setaddress(inetaddress addr) getport(), setport(int port) getdata(), setdata(byte[] buf), etc. La Classe InetAddress Classe con cui vengono rappresentati gli indirizzi Internet, astraendo dal modo con cui vengono specificati (a numeri o a lettere) Portabilità e trasparenza No costruttori, utilizzo di tre metodi statici: public static InetAddress getbyname(string hostname); restituisce un oggetto InetAddress rappresentante l host specificato (come nome o indirizzo numerico); con il parametro null ci si riferisce all indirizzo di default della macchina locale public static InetAddress[] getallbyname(string hostname); restituisce un array di oggetti InetAddress; utile in casi di più indirizzi IP registrati con lo stesso nome logico public static InetAddress getlocalhost(); restituisce un oggetto InetAddress corrispondente alla macchina locale; se tale macchina non è registrata oppure è protetta da un firewall, l indirizzo è quello di loopback: 127.0.0.1 Tutti possono sollevare l eccezione UnknownHostException se l indirizzo specificato non può essere risolto (tramite il DNS) Modelli e Applicazioni in RdC Materiale addizionale Java socket - 21 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 22
Schema di soluzione: il Client 1. Creazione socket ed eventuale settaggio opzioni: socket = new DatagramSocket(); socket.setxxx( ); 2. Interazione da console con l utente: BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Domanda "); String richiesta = stdin.readline(); 3. Creazione del pacchetto di richiesta con le informazioni inserite dall utente: packetout = DatagramUtility.buildPacket (addr, LineServer.PORT, richiesta); 4. Invio del pacchetto al server: socket.send(packetout); 5. Attesa del pacchetto di risposta: packetin = new DatagramPacket (buf, buf.length); socket.receive(packetin); 6. Estrazione delle informazioni dal pacchetto ricevuto: risposta = DatagramUtility.getContent(packetIN); Schema di soluzione: il Server 1. Creazione socket: socket = new DatagramSocket(PORT); 2. Attesa del pacchetto di richiesta: packet = new DatagramPacket (buf, buf.length); socket.receive(packet); 3. Estrazione delle informazioni dal pacchetto ricevuto: String richiesta = DatagramUtility.getContent(packet); StringTokenizer st = new StringTokenizer(richiesta); nomefile = st.nexttoken(); numlinea = Integer.parseInt(st.nextToken()); 4. Creazione del pacchetto di risposta con la linea richiesta: String linea = LineUtility.getLine(nomeFile, numlinea); packet = DatagramUtility.buildPacket( mittaddr, mittport, linea); 5. Invio del pacchetto al client: socket.send(packet); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 23 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 24
Datagram Utility public class DatagramUtility Metodo per creare un pacchetto da una stringa: static protected DatagramPacket buildpacket (InetAddress addr, int port, String msg) throws IOException ByteArrayOutputStream bostream = new ByteArrayOutputStream(); DataOutputStream dostream = new DataOutputStream(boStream); dostream.writeutf(msg); byte[] data = bostream.tobytearray(); return new DatagramPacket(data, data.length, addr, port); Metodo per recuperare una stringa da un pacchetto: static protected String getcontent (DatagramPacket dp) throws IOException ByteArrayInputStream bistream = new ByteArrayInputStream(dp.getData(), 0, dp.getlength()); DataInputStream distream = new DataInputStream(biStream); String msg = distream.readutf(); return msg; LineUtility public class LineUtility Metodo per recuperare una certa linea di un certo file: static String getline (String nomefile, int numlinea) String linea = null; BufferedReader in = null; try in = new BufferedReader( new FileReader(nomeFile)); catch (FileNotFoundException e) return linea = "File non trovato"; try for (int i=1; i<numlinea; i++) in.readline(); if ((linea = in.readline()) == null) linea = "Linea non trovata"; catch (IOException e) return linea = "Linea non trovata"; return linea; Modelli e Applicazioni in RdC Materiale addizionale Java socket - 25 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 26
Metodo per recuperare la linea successiva di un file già aperto in precedenza: static String getnextline(bufferedreader in) String linea = null; Line Client public class LineClient public static void main(string[] args) try if ((linea = in.readline()) == null) in.close(); linea = "Nessuna linea disponibile"; catch (FileNotFoundException e) return linea = "File non trovato"; catch (IOException e) linea = "Nessuna linea disponibile"; return linea; DatagramSocket socket=null; socket = new DatagramSocket(); socket.setsotimeout(30000); catch (SocketException e) System.exit(1); InetAddress addr=null; if (args.length == 0) addr = InetAddress.getByName(null); else addr = InetAddress.getByName(args[0]); catch(unknownhostexception e) System.exit(2); BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); String richiesta=null; Modelli e Applicazioni in RdC Materiale addizionale Java socket - 27 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 28
System.out.print("\n^D(Unix)/^Z(Win)+invio per uscire, solo invio per continuare: "); while (stdin.readline()!=null) System.out.print("Nome del file? "); String nomefile = stdin.readline(); System.out.print("Numero linea? "); int numlinea = Integer.parseInt(stdIn.readLine()); richiesta = nomefile+" "+numlinea; catch (Exception e) System.out.print("\n^D(Unix)/^Z(Win) +invio per uscire, solo invio per continuare: "); DatagramPacket packetout = DatagramUtility.buildPacket (addr, LineServer.PORT, richiesta); socket.send(packetout); catch (IOException e)/* come sopra */ byte[] buf = new byte[256]; packetin = new DatagramPacket(buf, buf.length); socket.receive(packetin); catch (IOException e)/* come sopra */ String risposta=null; risposta = DatagramUtility.getContent(packetIN); System.out.println("Risposta: " + risposta); catch (IOException e)/* come sopra */ System.out.print("\n^D(Unix)/^Z(Win)+invio per uscire, solo invio per continuare: "); // while catch(exception e) System.out.println("LineClient: termino.."); socket.close(); DatagramPacket packetin=null; Modelli e Applicazioni in RdC Materiale addizionale Java socket - 29 Modelli e Applicazioni in RdC Materiale addizionale Java socket - 30
Line Server public class LineServer public static final int PORT = 4445; public static void main(string[] args) DatagramSocket socket = null; try socket = new DatagramSocket(PORT); catch (SocketException e) System.exit(1); while (true) System.out.println("\n In attesa di richieste..."); DatagramPacket packet=null; InetAddress mittaddr=null; int mittport=0; byte[] buf = new byte[256]; packet = new DatagramPacket(buf, buf.length); socket.receive(packet); mittaddr = packet.getaddress(); mittport = packet.getport(); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 31 catch(ioexception e) e.getmessage()); String nomefile; int numlinea; String richiesta = DatagramUtility.getContent(packet); StringTokenizer st = new StringTokenizer(richiesta); nomefile = st.nexttoken(); numlinea = Integer.parseInt(st.nextToken()); catch(exception e)/* come sopra */ String linea = LineUtility.getLine(nomeFile, numlinea); packet = DatagramUtility.buildPacket( mittaddr, mittport, linea); socket.send(packet); catch(ioexception e)/* come sopra */ // while catch(exception e) System.out.println("LineServer: termino.."); socket.close(); Modelli e Applicazioni in RdC Materiale addizionale Java socket - 32