Docente: Gabriele Lombardi lombardi@dsi.unimi.it Networking (cenni) Docente: Gabriele Lombardi lombardi@dsi.unimi.it © 2010 - CEFRIEL
The present original document was produced by CEFRIEL and the Teacher for the benefit and internal use of this course, and nobody else may claim any right or paternity on it. No right to use the document for any purpose other than the Intended purpose and no right to distribute, disclose, release, furnish or disseminate it or a part of it in any way or form to anyone without the prior express written consent of CEFRIEL and the Teacher. © copyright Cefriel and the Teacher-Milan-Italy-23/06/2008. All rights reserved in accordance with rule of law and international agreements. © 2010 - CEFRIEL
Sommario Problematiche Strumenti di base Il client Il server SLIDE CONTENUTO Problematiche Problematiche di comunicazione sulla rete Strumenti di base URI, URL, indirizzi e porte Il client Usare le socket come client Il server Usare le socket nei server Modelli di server Server sequenziali e concorrenti © 2010 - CEFRIEL
Problematiche di networking Comunicazione: trasferimento dati su una tratta, instradamento; assegnazione di un indirizzo per ogni host (IP): indirizzi del tipo 159.149.140.6 (IPv4); 4 numeri tra 0 e 255; associazione nomi (DNS); utilizzo di protocolli well-known (ftp, HTTP, …). Altre problematiche: trasferimento dati “manualmente”: utilizzo stream (java.io.*) tramite socket; conversione dati host2network e network2host; accesso a parametri di basso livello (campi dei pacchetti); Authentication, Permissions, Proxy, Cookies, … © 2010 - CEFRIEL
Strumenti di base: URI e URL URI (Unified Resource Identifier): rappresenta l’identificativo univoco di una risorsa; è della forma: [scheme:]scheme-specific-part[#fragment] mailto:java-net@java.sun.com in particolare la versione gerarchica è: [scheme:][//authority][path][?query][#fragment] http://java.sun.com/j2se/1.3/ La classe java.net.URI: permette parsing e validazione dell’URI; permette di ottenerne l’URL associato. URL (Unified Resource Locator): rappresenta la locazione da cui è possibile reperire una risorsa; segue lo schema gerarchico di URI; permette di accedere ai dati della risorsa tramite stream: URL url = new URL(“http://www.google.com”); InputStream is = url.openStream(); © 2010 - CEFRIEL
Strumenti di base: indirizzi InetAddress, Inet4Address, Inet6Address: indirizzi IP (Interenet Protocol v4 e v6); generato tramite factory method: InetAddress addr1 = InetAddress.getByName(“159.149.140.6”); InetAddress addr2 = InetAddress.getByName(“google.com”); si noti che addr2 viene risolto tramite DNS; porte (interi positivi): l’indirizzo IP identifica un host, la porta identifica il servizio richiesto (processo in ascolto sulla porta); InetSocketAddress: rappresenta un indirizzo di una socket; è definito come unione di un IP e una porta: InetSocketAddress addr = new InetSocketAddress( InetAddress.getByName(“google.com”), 80); © 2010 - CEFRIEL
Socket attive (client) java.net.Socket: rappresenta la “cornetta del telefono”, un capo della comunicazione bidirezionale realizzabile con TCP/IP; è identificata da un indirizzo InetSocketAddress; stabilisce la connessione con un altro InetSocketAddress; consente di aprire due canali di comunicazione: Socket soc = new Socket(“www.google.com”, 80); InputStream is = soc.getInputStream(); OutputStream os = soc.getOutputStream(); a questo punto la comunicazione è stabilita; delle eccezioni possono indicarci il fallimento; va chiusa al termine della comunicazione: soc.close(); non si può chiudere parzialmente questo tipo di socket (al più disabilitare input oppure output). java.net.DatagramSocket, java.net.MulticastSocket: strumenti per la comunicazione a datagramma (UDP). © 2010 - CEFRIEL
Socket attive (client) // Creo la socket di comunicazione col server: InetAddress indirizzo = InetAddress.getByName(servername); Socket soc = new Socket(indirizzo, porta); // Chi siamo? System.out.println("Io sono: " + soc.getLocalAddress() + "/" + soc.getLocalPort()); System.out.println("Io cerco: " + soc.getInetAddress() + "/" + soc.getPort()); // Ottengo gli stream di comunicazione: OutputStream os = soc.getOutputStream(); InputStream is = soc.getInputStream(); // Un po’ di comodità! Writer writer = new OutputStreamWriter(os); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); // Comunico la richiesta HTTP: String richiesta = inizioRichiesta + risorsa + "\n\n"; writer.write(richiesta); writer.flush(); // Lettura della risposta: String linea; while((linea=reader.readLine())!=null) { System.out.println(linea); } // Fine: reader.close(); writer.close(); vedere 05_Networking\ClientFuffo con: esempio di base client esempio di base server © 2010 - CEFRIEL
Socket passive (server) java.net.ServerSocket: rappresentano servizi in ascolto per richieste; non vengono usate per comunicare … … ma per accettare comunicazioni; ServerSocket ssoc = new ServerSocket(numPorta); Socket soc = ssoc.accept(); // Attendo l’arrivo di una richiesta! a questo punto soc è connessa con il client. SocketImpl, DatagramSocketImpl: implementazioni astratta delle socket; consente di sostituire l’implementazione concreta; utile se si vuole usare una propria implementazione. SocketImplFactory, DatagramSocketImplFactory: interfacce da implementare se si vuole realizzare una propria implementazione delle socket TCP e UDP. © 2010 - CEFRIEL
Socket passive (server) // Creo la socket: ServerSocket ss = new ServerSocket(porta); while (true) { // Per sempre! // Aspetto che qualcuno si connetta a me: Socket soc = ss.accept(); System.out.println("Io sono: " + soc.getLocalAddress() + "/" + soc.getLocalPort()); System.out.println("Io cerco: " + soc.getInetAddress() + "/" + soc.getPort()); // Ottengo gli stream di comunicazione: OutputStream os = soc.getOutputStream(); InputStream is = soc.getInputStream(); // Un po’ di comodità! Writer writer = new OutputStreamWriter(os); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); // Ottengo in ingresso i dati: System.out.println("Richiesta: " + reader.readLine()); // Mando una risposta: writer.write("Ciao!\n"); writer.flush(); // Chiudo tutto: reader.close(); writer.close(); } vedere 05_Networking\ClientFuffo con: esempio di base client esempio di base server vedere 04_Concurrency\Chat con: server concorrente client che comunica col server mini-protocollo proprietario © 2010 - CEFRIEL
Tipologie di server Lo scopo del server è quello di soddisfare richieste … … più richieste possono arrivare assieme. ServerSocket mantiene una lista di richieste pendenti: quindi il precedente programma soddisfa tutte le richieste in arrivo (entro i limiti) senza perderne nessuna … … ma ogni client deve attendere “in fila” prima di poter essere servito dall’unico processo. La soluzione consiste nel cambiare modello di server: i modelli classici sono: server sequenziale (quello mostrato precedentemente); server concorrente (delega il compito di rispondere a un processo); server concorrente con select (ascolto su porte multiple). Soluzione: passare al modello concorrente. © 2010 - CEFRIEL
Esempio di server concorrente // Faccio sempre la stessa cosa: while (true) { try { // Ascolto la socket: Socket soc = ssoc.accept(); // Gestisco la comunicazione in un thread separato: esecutore.execute( new GestoreMessaggioEntrante(soc) { public void run() { try { // Connessione stabilita, ottengo il messaggio: ObjectInputStream ois = new ObjectInputStream(soc.getInputStream()); Messaggio msg = (Messaggio)(ois.readObject()); // Fine comunicazione: ois.close(); // Gestisco il messaggio: System.err.println("Ricevuto messaggio da: " + msg.getMittente()); ricevuto(soc.getInetAddress(),msg); } catch (Exception e) { e.printStackTrace(); } } }); vedere 04_Concurrency\Chat con: server concorrente client che comunica col server mini-protocollo proprietario © 2010 - CEFRIEL