Esercizi in Laboratorio SOCKET PDF
Document Details
Uploaded by Deleted User
Tags
Summary
This document is a Java socket programming guide. The document explores Java socket programming details. The document guides developers on how to communicate with systems by using TCP/IP. It outlines network communication principles and explains how different Java classes such as InetAddress, ServerSocket, and Socket facilitate client-server interactions.
Full Transcript
UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 1 ESERCIZI IN LABORATORIO JAVA SOCKET Java socket: caratteristiche della comunicazione Si è detto che un socket è come una porta di comunicazione e tutto ciò che è in grado di comunicare tramite il proto- collo stan...
UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 1 ESERCIZI IN LABORATORIO JAVA SOCKET Java socket: caratteristiche della comunicazione Si è detto che un socket è come una porta di comunicazione e tutto ciò che è in grado di comunicare tramite il proto- collo standard TCP/IP può collegarsi a un socket e comunicare attraverso di esso; sappiamo anche che le informazioni “spedite” da un socket a un altro prendono il nome di pacchetti TCP/IP. Riassumiamo le caratteristiche fondamentali della comunicazione: tipicamente, la comunicazione è punto-punto (unicast), ma esistono estensioni che permettono comunicazioni multi-punto (multicast); la sorgente della comunicazione deve conoscere l’identità (indirizzo IP e numero di porta) del destinatario; la serializzazione (trasformazione tra dati strutturati e sequenze di byte) e il marshalling (conversione tra rappresen- tazioni di dati diversi) sono a carico delle applicazioni. Le operazioni necessarie per un trasferimento di dati tra due host sono le seguenti: 1 un host che si comporta da server apre un canale di comunicazione su una determinata porta e rimane in ascolto, in attesa di una richiesta di connessione (ServerSocket); 2 un host client fa una richiesta di connessione a un server (con indirizzo IP e address port conosciuti: socket sul client); 3 il server accetta la connessione del client e così viene instaurato un canale di comunicazione tra i due host. Server Client ServerSocket Port Port TCP Socket IP Address IP Address Java utilizza la classe Socket per la creazione degli oggetti che permettono di utilizzare i socket e quindi di stabilire un canale di comunicazione tra un client e un server attraverso il quale si comunica utilizzando due stream particolari, specializzati per i socket, uno per l’input e l’altro per l’output. Vediamo dapprima singolarmente le classi che Java mette a disposizione per l’utilizzo dei socket e successivamente implementiamo un server e un client: classe InetAddress; classe ServerSocket; classe Socket. Classe InetAddress Un indirizzo di rete IP v4 è costituito da 4 numeri (da 0 a 255) separati ciascuno da un punto e il DNS permette di uti- lizzare in alternativa il nome simbolico per individuare un particolare host. La classe InetAddress mette a disposizione diversi metodi per astrarre dal particolare tipo di indirizzo speci cato (a numeri o a lettere), occupandosi essa stessa di e ettuare le dovute traduzioni. 120 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP ESERCIZI IN LABORATORIO 1 Il diagramma completo della classe è il seguente: Classe InetAddress Metodi modificatori InetAddress[] getAllByName(String host) boolean equals(Object obj) InetAddress getByAddress(byte[] addr) int hashCode() InetAddress getByAddress(String host, byte[] addr) String toString() InetAddress getByName(String host) byte[][] lookupAllHostAddr(String host) InetAddress getLocalHost() Object run() byte[] getAddress() String getCanonicalHostName() String getHostAddress() String getHostByAddr(byte[] addr) boolean isAnyLocalAddress() boolean isLinkLocalAddress() boolean isLoopbackAddress() boolean isMCGlobal() boolean isMCLinkLocal() boolean isMCNodeLocal() boolean isMCOrgLocal() boolean isMCSiteLocal() boolean isMulticastAddress() boolean isSiteLocalAddress() Non sono previsti costruttori e l’unico modo per creare un oggetto di classe InetAddress prevede l’utilizzo di metodi statici, e in particolare: public static InetAddress getByName(String host) restituisce un oggetto InetAddress rappresentante l’host speci cato nel parametro host; l’host può essere speci - cato sia con il nome sia con l’indirizzo IP numerico e se si speci ca null come parametro, ci si riferisce all’indirizzo di default della macchina locale; public static InetAddress getLocalHost() viene restituito un InetAddress corrispondente alla macchina locale; se tale macchina non è registrata, oppure è protetta da un rewall, l’indirizzo è quello di loopback: 127.0.0.1. Se l’indirizzo speci cato non può essere risolto tramite il DNS; questi metodi possono sollevare l’eccezione UnknownHostException. Di particolare utilità sono i tre metodi illustrati di seguito: 1 public String getHostName() restituisce il nome dell’host che corrisponde all’indirizzo IP dell’InetAddress; se il nome non è ancora noto (per esempio se l’oggetto è stato creato speci cando un indirizzo IP numerico), verrà cercato tramite il DNS; se tale ricerca fallisce, verrà restituito l’indirizzo IP numerico sotto forma di stringa. 2 public String getHostAddress() simile al precedente, restituisce però l’indirizzo IP numerico, sotto forma di stringa, corrispondente all’oggetto InetAddress. 3 public byte[] getAddress() l’indirizzo IP numerico restituito sarà sotto forma di matrice di byte; l’ordinamento dei byte è high byte rst (che è l’ordinamento tipico della rete). Per esempio, con: String indirizzo = InetAddress.getLocalHost().getHostAddress(); l’oggetto indirizzo conterrà l’indirizzo IP della macchina locale. 121 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 1 ESERCIZI IN LABORATORIO La gura che segue rappresenta un esempio del nome dell’host riconosciuto dalla classe InetAddress e dal DNS. Classe ServerSocket La classe ServerSocket, il cui diagramma è il seguente, viene utilizzata per accettare connessioni da parte del client. Classe ServerSocket Metodi costruttori Metodi modificatori ServerSocket() void setSocketFactory(SocketImplFactory fac) ServerSocket(int port) ServerSocketChannel getChannel() ServerSocket(int port, int backlog) InetAddress getInetAddress() ServerSocket(int port, int backlog, int getLocalPort() InetAddress bindAddr) SocketAddress getLocalSocketAddress() int get/setReceiveAddress() boolean get/setReuseAddress() int get/setSoTimeout() boolean isBound() boolean isClosed() String toString() Socket accept() void bind(SocketAddress endpoint) void bind(SocketAddress endpoint, int backlog) void close() void implAccept(Socket s) Questa classe deve essere istanziata passando come parametro il numero della porta su cui il server sarà in ascolto: ServerSocket(int port). L’unico metodo realmente necessario è accept(): mediante tale metodo l’oggetto rimane in attesa di richiesta di connessioni da parte di un client sulla porta speci cata nel costruttore. Quando una richiesta di connessione va a buon ne viene creato il canale di collegamento e il metodo restituisce un oggetto Socket connesso con il client. 122 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP ESERCIZI IN LABORATORIO 1 Per esempio: il server si mette in ascolto sulla porta 6789; quando riceve una richiesta di connessione, viene creato un oggetto client di classe Socket (che vedremo in seguito); questo oggetto rappresenta il canale di comunicazione server-client; con la terza istruzione si chiude il server: ciò implica una comu- nicazione di tipo Unicast, dato che, dopo avere instaurato una Vediamo a lato la chiosa delle singole istruzioni: connessione, il server non rimane più in ascolto. Per poter utilizzare una connessione multicast (che realizzeremo più avanti), si dovrebbe istanziare un thread per ogni connessione e ettuata, in modo da lasciare il server sempre in ascolto. Classe Socket La classe Socket permette di de nire una connessione client-server via TCP su entrambi i lati, sia client che server. La di erenza tra client e server sta nella modalità di creazione di un oggetto di questo tipo: nel server l’oggetto Socket viene creato dal metodo accept() della classe ServerSocket; il client provvede a creare un’istanza di Socket: per creare un socket con un server in esecuzione su un dato host basta creare un oggetto di classe Socket speci cando nel costruttore l’indirizzo Internet dell’host e il numero di porta. Dopo che l’oggetto Socket è stato istanziato, è possibile ottenere (con appositi metodi) due stream (uno di input e uno di output): con essi è possibile comunicare con l’host, e riceverne messaggi. Il diagramma della classe Socket è il seguente: Classe Socket Metodi costruttori Metodi modificatori Socket() void setSocketImplFactory(SocketImplFactory fac) Socket(SocketImpl port) SocketChannel getChannel() Socket(String host, int port) InetAddress getInetAddress() Socket(InetAddress address, int port) InputStrem getInputStream() Socket(String host, int port, InetAddress boolean get/setKeepAlive() localAddr, int localPort) InetAddress getLocalAddress() Socket(InetAddress address, int port, int getLocalPort() InetAddress localAddr, int localPort) SocketAddress getLocalSocketAddress() boolean get/setOOBInline() OutputStream getOutputStream() int getPort() int get/VHW5HFHLYH%XҬHU6L]H() SocketAddress get/getRemoteSocketAddress() boolean get/setReuseAddress() int get/VHW6HQG%XҬHU6L]H() int getSolLinger() int get/setSoTimeout() boolean get/setTopNoDelay() int get/VHW7UDҬLF&ODVV() boolean isBound() boolean isClosed() boolean isConnected() boolean isInputShutDown() / isOutputShutDown() void setSoLinger(boolean on, int linger) String toString() void bind(SocketAddress bindpoint) void close() void connect(SocketAddress endpoint) void sendUrgentData(int data) void shutdownInput() / shutdownOutput() 123 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 1 ESERCIZI IN LABORATORIO Qualsiasi metodo che prenda in ingresso un InputStream o un OutputStream può comunicare con l’host in rete: una volta creato il Socket si può comunicare in rete tramite l’utilizzo degli stream. I costruttori della classe Socket sono i seguenti: public Socket (String host, int port) throws IOException; public Socket (InetAddress address, int port) throws IOException. Viene creato un oggetto Socket connettendosi con l’host speci cato (sotto forma di stringa o di InetAddress) alla porta speci cata. Se sull’host e sulla porta speci cata non c’è un server in ascolto, viene generata un’IOException e viene speci cato il messaggio connection refused. Alcuni metodi tra i più utilizzati sono i seguenti: public InetAddress getInetAddress() restituisce un oggetto Inet-Address corrispondente all’indirizzo dell’host con il quale il socket è connesso; public InetAddress getLocalAddress() restituisce un oggetto Inet-Address corrispondente all’indirizzo locale al quale il socket è collegato; static InetAddress getByName(String hostname) restituisce una istanza di InetAddress rappresentante l’host speci cato; public int getPort() restituisce il numero della porta dell’host remoto con il quale il socket è collegato; public int getLocalPort() restituisce il numero di porta locale con la quale il socket è collegato. Quando si crea un socket, come già detto, ci si collega con un server su un determinato host, che è in ascolto su una certa porta; sulla macchina locale viene creato il socket su una determinata porta assegnata dal sistema operativo (il primo numero libero): public InputStream getInputStream() throws IOException public OutputStream getOutputStream() throws IOException Quando si comunica attraverso connessioni TCP, i dati vengono suddivisi in pacchetti (IP packet), quindi è consigliabile utilizzare degli stream “bu erizzati” evitando così di avere pacchetti contenenti poche informazioni. La de nizione dei due stream, rispettivamente di input e di output, da parte di un server verso un client, è per esempio la seguente: Dopo questa de nizione l’uso dei socket diventa quindi trasparente: su questi oggetti si utilizzano i metodi readLine() e println()! L’ultimo metodo che descriviamo è: public synchronized void close() throws IOException Con questo metodo viene chiuso il socket (e quindi la connessione) e tutte le risorse che erano in uso vengono rila- sciate. I dati bu erizzati verranno comunque spediti prima della chiusura del socket, chiusura anche solo di uno dei due stream associati ai socket che comporterà automaticamente la chiusura del socket stesso. 124 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP ESERCIZI IN LABORATORIO 1 Nei metodi precedenti può essere lanciata un’IOException, a signi care che ci sono stati problemi sulla connessione: questo succede quando uno dei due programmi che utilizza il socket chiude la connessione e quindi l’altro programma potrà ricevere una tale eccezione. La realizzazione di un client TCP in Java Possiamo ora realizzare un client: per comunicare con un host remoto usando il protocollo TCP/IP, si deve creare, per prima cosa, un oggetto Socket con tale host, speci cando l’indirizzo IP dell’host e il numero di porta (naturalmente sull’host remoto dovrà essere presente un server in “ascolto” su tale porta). Possiamo utilizzare indistintamente uno dei due costruttori della classe Socket sopra descritta: public Socket (String host, int port) throws IOException; public Socket (InetAddress address, int port) throws IOException. Con questa istruzione viene creata una connessione con un’applicazione server (che nel frattempo è in attesa in una accept()) e restituisce il relativo socket. De niamo le variabili della nostra classe: Realizziamo ora la parte di un metodo che esegue le operazioni per aprire un socket con un server che si trova a un certo indirizzo (nomeServer) ed è in ascolto su una certa porta (portaServer) restituendo come parametro di ritorno un oggetto della classe Socket. Una volta creato un oggetto Socket otteniamo gli stream a esso associati tramite i due metodi prima descritti della classe Socket: a questo punto, la comunicazione può avere inizio, cioè il client può scrivere sull’OutputStream, come si fa con un normale stream, e ricevere dati dal server leggendo dall’InputStream. L’esempio seguente permette di leggere una stringa di testo dalla tastiera di un client. Esso invia la stringa a un server, il quale la modi ca trasformandola in maiuscolo e la restituisce al client. La comunicazione avviene sulla porta 6789 sul server locale localhost. Naturalmente, non possiamo mandarlo in esecuzione senza aver realizzato il server, ma per ora lo scriviamo e lo commentiamo, realizzando il server successivamente. 125 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 1 ESERCIZI IN LABORATORIO De niamo le variabili da utilizzare nella classe. Quindi de niamo il metodo che stabilisce la connessione con il server: Abbiamo creato un socket mediante il costruttore: miosocket = new Socket(nomeserver,portaserver); Trattandosi di server locale avremmo anche potuto utilizzare la seguente istruzione: miosocket = new Socket(InetAddress.getLocalHost(), 6789); Per le comunicazioni I/O abbiamo de nito tre oggetti, il primo della classe Bu eredReader per e ettuare l’input da ta- stiera e gli altri due, rispettivamente, della classe DataOutputStream e Bu eredReader per scrivere e leggere sul socket. De niamo un secondo metodo che e ettua la conversazione: leggiamo la stringa inserita dall’utente e la scriviamo sullo stream del miosocket: quindi ci mettiamo in attesa della risposta del server mediante la inDalserver.readLine(); quando riceviamo la risposta la visualizziamo sullo schermo e terminiamo l’elaborazione chiudendo la porta con miosocket.close(). 126 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 5 ESERCIZI IN LABORATORIO IL PROTOCOLLO UDP NEL LINGUAGGIO JAVA Client e server UDP in Java Il protocollo UDP ha caratteristiche diverse dal protocollo TCP: UDP non è orientato alla connessione e quindi tra due host non si crea uno stream stabile. L’avvio di una comunicazione avviene senza handshaking e la consegna non è garantita; al contrario i controlli sull’in- tegrità vengono eseguiti come in TCP. Uno dei principali vantaggi di UDP è che, grazie alla sua semplicità o re un servizio molto rapido e non richiede han- dshaking (per questo viene spesso utilizzato per DNS). In questa esercitazione realizzeremo la comunicazione mediante protocollo UDP dove un mittente (UDPClient.java) trasmette un messaggio (datagram) a un destinatario (UDPServer.java). Ricordiamo che, in una comunicazione dati “connectionless o datagram”, il canale: trasporta messaggi; non è a dabile; ha il socket condiviso; non preserva l’ordine delle informazioni. Inoltre l’ordine di arrivo dei pacchetti non è necessariamente lo stesso di invio. Realizzare un sistema client-server UDP consiste nell’implementare un programma che e ettui i seguenti passi fon- damentali. Per il client: crea il socket; manda richiesta sul socket (composto da indirizzo, porta e messaggio); riceve dati dal socket; chiude il socket. Per il server: crea il socket ripete le seguenti operazioni: − si mette in attesa delle richieste in arrivo; − riceve il messaggio dal socket; − invia la risposta sul socket al client che ha fatto una richiesta; chiude il socket. La comunicazione UDP viene realizzata in Java mediante la classe DatagramSocket. Classe DatagramSocket La classe Java DatagramSocket usa il protocollo UDP per trasmettere dati attraverso i socket: permette a un client di con- nettersi a una determinata porta di un host per leggere e scrivere dati impacchettati attraverso la classe DatagramPacket. L’indirizzo dell’host destinatario è sul DatagramPacket. I principali metodi della DatagramSocket(..) sono i seguenti. Metodi costruttori: void DatagramSocket() throws SocketException void DatagramSocket(int porta) throws SocketException 144 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP ESERCIZI IN LABORATORIO 5 Metodi per ricevere/trasmettere: void send(DatagramPacket pacchettoDati) throws IOException void receive(DatagramPacket pacchettoDati) throws IOException Il metodo receive() blocca il chiamante no a quando un pacchetto è ricevuto void setSoTimeout(int timeout) throws SocketException usando setSoTimeout() il chiamante di receive() si blocca dopo timeout millisecondi. In ne, il “solito” metodo per chiudere la connessione: void close() Classe DatagramPacket La classe DatagramPacket è la classe Java che permette di rappresentare i pacchetti UDP da inviare e ricevere sui socket di tipo datagram. Il costruttore della classe è il seguente: public DatagramPacket(byte EXҬHU>@ int lunghezza, InetAddress indirizzo, int porta) Il client crea un oggetto di DatagramPacket passando al costruttore: il contenuto del messaggio: un array di lunghezza caratteri; l’indirizzo IP del server; il numero di porta su cui il server è in ascolto. Il server, per ricevere un messaggio, crea un oggetto di DatagramPacket de nendone la lunghezza massima: public DatagramPacket(byte EXҬHU>@ int lunghezza) I principali metodi della classe DatagramPacket sono: A Per la gestione dell’indirizzo IP: void setAddress(InetAddress indirizzo): setta il valore dell’indirizzo IP; InetAddress getAddress(): restituisce l’indirizzo IP del’host da cui il pacchetto è stato ricevuto. B Per la gestione della porta: void setPort(int porta): setta il valore della porta; int getPort(): restituisce la porta della macchina remota da cui il pacchetto è stato ricevuto. C Per la gestione dei dati: void setData E\WH>@EXҬHU : inserisce i dati nel pacchetto; byte[] getData(): restituisce i dati del pacchetto. 145 UNITÀ 2 - I socket e la comunicazione con i protocolli TCP/UDP 5 ESERCIZI IN LABORATORIO Server UDP Scriviamo il server UDP: creiamo un DatagramSocket() sulla solita porta 6789 e de niamo i due bu er per i dati, rispet- tivamente per la ricezione e per la trasmissione, per esempio della medesima dimensione di 1024 byte. Una variabile booleana viene de nita per essere utilizzata come condizione di ripetizione/uscita dal ciclo. De niamo ora il datagramma e ci poniamo in attesa di ricevere dati da qualche client: Quando viene ricevuto un pacchetto, viene analizzato estraendo il messaggio, individuando la lunghezza impostata alla trasmissione per eliminare i caratteri super ui presenti nel bu er, che ricordiamo essere di 1024 byte; Sempre dal pacchetto ricevuto vengono individuati i parametri per la trasmissione della risposta, cioè l’indirizzo e il numero di porta del client: Viene preparata la risposta, che in questo caso non è altro che il messaggio ricevuto trasformato in maiuscolo, viene creato il datagramma in uscita e viene inviato al client: 146