La comunicazione di rete è una realtà a cui siamo ampiamente abituati. Computer di tutto il mondo, connessi dall‘immensa rete Internet, comunicano tra di loro per scambiare dati di ogni tipo. I progettisti di Java hanno sempre tenuto in considerazione l‘ambiente Internet, per cui la programmazione di rete in questo linguaggio è più semplice che in altri. Prima di avventurarsi nel mondo della programmazione di rete è necessario chiarire alcuni concetti.
Pila di protocolli
Uno dei concetti chiave del networking è il protocollo. Il protocollo è un insieme di regole a cui gli attori in gioco si attengono per poter scambiare informazioni tra di loro. La comunicazione in rete è una realtà talmente complessa da richiedere una serie di protocolli, disposti uno sopra l‘altro, ciascuno specializzato in un compito preciso. La comunicazione avviene solo tra protocolli confinanti, come si può vedere in Figura 1:Pila di protocolli.jpg: Figura 1 – Esempio di pila di protocolliA livello applicativo si trovano protocolli come HTTP, il protocollo del WEB, FTP, un protocollo per la trasmissione di file attraverso la rete, POP e SMTP, i comuni protocolli E-Mail e TELNET, che permette di aprire sessioni di lavoro remote. Questi si appoggiano su una coppia di protocolli di trasporto, TCP e UDP, le cui differenze verranno spiegate nei prossimi capitoli. Infine TCP e UDP utilizzano il comune protocollo di rete IP. La pila di protocolli comprende in realtà ben sette livelli, ma ai fini della presente trattazione sarà sufficiente prendere in considerazione questi tre.Il package java.net presenta classi che permettono di sfruttare i protocolli TCP e UDP in maniera indipendente dal sistema ospite. Prima di proseguire è importante capire la differenza tra questi due protocolli.
TCP
Il protocollo TCP consente di creare una connessione affidabile tra due computer connessi ad Internet, in modo da offrire un canale di comunicazione basato su stream, in modo simile a quanto si farebbe con un‘unità a disco. Il funzionamento interno del protocollo TCP è piuttosto complesso: la comunicazione tra i due host viene infatti suddivisa in pacchetti di informazione che seguono percorsi differenti attraverso la rete e che vengono ricomposti e riordinati solo al loro arrivo. La rete è un ambiente insidioso, in cui spesso i pacchetti si perdono o vengono scartati dai router per eccesso di traffico: il protocollo TCP garantisce che per ogni pacchetto perso ne venga automaticamente rispedito uno identico, in modo che l‘utente non si accorga di niente. L‘utente viene avvisato solamente se si verifica un errore irrimediabile.
UDP
Il protocollo UDP fornisce un modello di comunicazione orientato al messaggio, invece che alla connessione. Il protocollo fornisce un meccanismo per spedire pacchetti di dati indipendenti tra di loro, detti datagrammi, per i quali non è garantita la ricezione. Spedire datagrammi è come inviare una serie di lettere attraverso il sistema postale: queste ultime possono arrivare in qualunque ordine, o non arrivare affatto. Il vantaggio di questo protocollo, per certi versi così inaffidabile è la velocità , che è decine di volte superiore a quella del TCP. Esistono applicazioni per le quali la perdita occasionale di un pacchetto è meno importante della rapidità di consegna: un esempio tipico sono le applicazioni di streaming video, in cui un fotogramma perso è meno importante di un fotogramma giunto in ritardo.
Indirizzi IP e porte
Come già precisato, TCP e UDP si appoggiano entrambi sul protocollo di rete IP. Un protocollo di rete ha il compito di instradare i pacchetti di dati dalla macchina che trasmette a quella che riceve, passando attraverso i router, o sistemi intermedi, dei calcolatori specializzati nello smistamento di traffico di rete.Per comunicare con un computer su Internet è necessario specificare un indirizzo composto da due elementi: l‘indirizzo IP e la porta. L‘indirizzo IP è un numero a 32 bit che viene rappresentato attraverso quattro cifre comprese tra 0 e 255 separate da un punto (tipo 167.128.10.15), e identifica in maniera univoca la macchina su Internet, la porta è un intero a 16 bit, compreso tra 0 e 65535, che specifica l‘applicazione a cui la comunicazione è destinata. L‘indirizzo IP viene spesso assimilato al numero civico di un palazzo, mentre la porta specifica l‘interno desiderato. I protocolli TCP e UDP utilizzano insiemi differenti di porte, per cui la porta 5001 TCP è diversa dalla porta 5001 UDP, ed entrambe possono lavorare contemporaneamente sulla stessa macchina. Le prime 1024 porte TCP sono riservate al sistema operativo, e costituiscono la via di accesso a servizi noti presenti su quasi tutti i computer.
Nota: nel corso degli anni sono diventati evidenti i limiti di un meccanismo di indirizzamento basato su interi a 32 bit, che consentono un massimo di quattro miliardi di indirizzi. Il nuovo protocollo IPv6 ricorre ad indirizzi a 128 bit, un fatto che garantisce un numero di indirizzi IP pari al numero di stelle in cielo. L‘esistenza di questo nuovo protocollo non deve preoccupare i programmatori, vista la compatibilità all‘indietro.
Indirizzi URL
Il termine URL è un acronimo per Universal Resource Locator, un termine che indica che attraverso una URL è possibile specificare una determinata risorsa di rete, sia essa un file su un computer connesso ad Internet, una stampante, un database o altro, tramite un indirizzo simbolico universale. Una URL è una stringa che contiene tutti gli elementi di un indirizzo web: un identificatore di protocollo (HTTP, FTP e così via) seguito dal nome della risorsa separati dlla stringa “://”, ad esempio “https://www.mokabyte.it”. Il formato della risorsa dipende dal protocollo, ma di solito comprende uno o più componenti tra quelli illustrati di seguito:÷ Host Name: il nome della macchina su cui si trova la risorsa.
- Filename: il percorso verso il file sulla macchina.
- Port Number: il numero di porta a cui connettersi.
- Reference: un reference ad una specifica locazione all‘interno del file.Protocollo separatore Host name separatore indirizzo
Per ulteriori chiarimenti sul formato delle URL, cfr [1]. Il nome simbolico viene trasformato in un indirizzo numerico IP da un servizio Internet detto DNS, o Dynamic Naming System, il cui funzionamento esula dagli obbiettivi del presente trattato.
La classe URL
La classe URL è una classe fondamentale del package java.net: grazie a questa classe è possibile creare semplici applicazioni di rete.
Costruttori
Il primo costruttore permette di creare una URL a partire dal formato String in cui viene rappresentato:
URL(String spec)
I sucessivi costruttori permettono di creare una URL a partire da un gruppo dei suoi elementi principali:
URL(String protocol, String host, int port, String file) URL(String protocol, String host, String file)
L‘ultimo dei costruttori permette di creare una URL a partire da una URL preesistente che denota il contesto, seguita da una stringa che specifica l‘indirizzo della risorsa all‘interno dell‘host specificato dalla URL base:
URL(URL context, String spec)
Grazie a questo costruttore è possibile specificare una serie di risorse presenti nello stesso sito, ad esempio:
URL mokabyte = new URL("https://www.mokabyte.it/");URL articolo1 = new URL(mokabyte, "articolo1.html");URL articolo2 = new URL(mokabyte, "articolo2.html");
Ciascuno di questi costruttori può lanciare una MalformedUrlException, per cui è necessario racchiudere la chiamata all‘interno di un apposito blocco try-catch:
try {URL mokabyte = new URL("https://www.mokabyte.it/");} catch (MalformedURLException e) {e.printStackTrace();}
Metodi getXxx()
La classe URL dispone di diversi metodi get() che permettono di accedere ai diversi elementi che compongono l‘indirizzo:
getProtocol()getHost()getPort()getFile()getRef()
Questi metodi sono indipendenti dal costruttore usato. Si noti tuttavia che non tutte le URL contengono tutti gli elementi specificati.
Leggere da un URL
Leggere il contenuto di un URL è semplice, grazie all‘apposito metodoInputStream openStream() Quest‘ultimo restituisce un InputStream con il quale è possibile leggere direttamente dalla URL, con un programma come il seguente:
import java.net.*;import java.io.*;public class URLReader {public static void main(String[] args) throws Exception {URL mokabyte = new URL("https://www.mokabyte.it/");BufferedReader in = new BufferedReader(new InputStreamReader(mokabyte.openStream()));while ( true ) {String s = in.readLine();if ( s == null )break;elseSystem.out.println(s);}in.close();}}
A meno di errori di connessione, il programma dovrebbe mostrare il contenuto HTML del sito www.mokabyte.it.
Scrivere su una URL
La classe URL dispone di un altro metodo utile a comunicare con un host:URLConnection openConnection() Questo metodo restituisce un oggetto di tipo URLConnection, che stabilisce una connessione bi-direzionale tra un programma Java e una risorsa Internet. La classe URLConnection contiene molti metodi che permettono di comunicare con una URL attraverso la rete.
Molti di questi metodi sono utili solo nel contesto di una comunicazione basata su protocollo HTTP; per il resto i metodi più importanti sono quelli che permettono di leggere e scrivere sulla connessione:
InputStream getInputStream()OutputStream getOutputStream()
Il primo metodo permette di leggere da una URL in modo simile a quanto già si poteva fare con il metodo openStream() della classe URL.
L‘unica ragione per usare questo metodo per leggere da una URL è la necessità di creare una comunicazione bi-direzionale. Alcune pagine HTML consentono di inviare un input da inviare al server attraverso un form. Tale input viene generalmente processato da una servlet o da uno script CGI, che a sua volta invia una risposta sotto forma di pagina HTML. Le operazioni di scrittura su URL avvengono in modalità POST.
URL url = new URL("http://java.sun.com/cgi-bin/backwards");URLConnection connection = url.openConnection();connection.setDoOutput(true);PrintWriter out = new PrintWriter(connection.getOutputStream());out.println("string=" + stringToReverse);out.close();A queste righe si risponde con un frammento di codice come il seguente:BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));while ( true ) {String s = in.readLine();if ( s == null )break;elseSystem.out.println(s);} in.close();
L‘interazione con servlet o script CGI esula dagli obiettivi del presente trattato. Chi fosse interessato ad approfondire l‘argomento può trovare informazioni su [2].
Conclusioni
Questo mese sono stati introdotti i concetti di base della programmazione di rete. Tra questi, è stato illustrato il concetto di pila di protocolli, la differenza tra TCP e UDP e l‘indirizzamento IP su Internet. Infine, grazie alle classi URL e URLConnection è stato possibile mostrare alcuni esempi funzionanti di programmi di rete in Java. Il prossimo mese verrà approfondito il protocollo TCP e le classi che ne permettono l‘utilizzo.
Riferimenti
[1]
A Beginner‘s Guide to URLs
http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/Demo/url-primer.html
[2]
Manuale Pratico di Java, Volume 2 (Cap. 1: Networking Avanzato)
https://www.mokabyte.it/manualejava2/vol2.htm
Risorse
Di seguito è riportato il codice relativo alla classe URLReader
import java.net.*;import java.io.*; public class URLReader {public static void main(String[] args) throws Exception {URL mokabyte = new URL("https://www.mokabyte.it/");BufferedReader in = new BufferedReader(new InputStreamReader(mokabyte.openStream()));while ( true ) {String s = in.readLine();if ( s == null )break;elseSystem.out.println(s);}in.close();}}