Java/Socket
L'accesso ai socket nel in Java avviene tramite l'uso delle classi e delle interfacce presenti nel package java.net
. Un'applicazione può, quindi, accedere a flussi di dati su reti basate sui protocolli TCP/IP e UDP/IP.
Java |
categoria · sviluppo · modifica |
Guida alla programmazioneJava/Introduzione - Specifica di linguaggioJava/Tipi di dato - Libreria standard |
Si utilizzano in particolare le seguenti classi:
- InetAddress, per la gestione degli indirizzi IP
- ServerSocket, per la creazione di socket lato server
- Socket, per la creazione di socket lato client
- DatagramSocket, implementa i socket per la trasmissione senza connessione
- MulticastSocket, fornisce supporto per i socket di tipo multicast
Indirizzo IP
modificaIn Java un indirizzo IP è rappresentato dalla classe InetAddress
: questa fornisce tutti quei metodi necessari a manipolare un indirizzo internet, necessario all'instradamento dei dati sulla rete. In particolare:
getAllByName(String host)
- è un metodo che ritorna tutti gli indirizzi internet di un host dato il suo nome in forma estesa (esempio:getAllByName("www.wikipedia.org")
)getByName(String host)
- ritorna un oggettoINetAddress
che rappresenta l'indirizzo IP dell'host. [1]getHostName()
ritorna una stringa rappresentante il nome dell'host.
Socket Lato Server
modificaPer realizzare un canale di comunicazione Client/Server occorre la creazione di un programma Server che rimane in ascolto su una determinata porta, e di un programma Client che, da remoto, lo invochi.
Per la creazione del programma Server in Java è necessario seguire i seguenti passaggi:
- Importare i package
java.io
ejava.net
per poter utilizzare le classiSocket
eServerSocket
- Intercettare l'eccezione
IOException
che deve essere gestita (tramitetry
ecatch
) o propagata (tramitethrows
), dato che vengono richiamati metodi delle classi che appartengono ai packagejava.io
ejava.net
. - Creare un oggetto
ServerSocket
, utilizzando il costruttoreServerSocket(int port)
che si aspetta come parametro la porta del Server in ascolto per il servizio da attivare. Ad esempio:
ServerSocket server = new ServerSocket(9999);
Da notare che il numero corrispondente alla porta di ascolto non è una stringa.
- Utilizzare il metodo
accept()
dell'oggettoServerSocket
per poter accettare le chiamate Client su un oggettoSocket
:
Socket client = server.accept();
Il metodo che viene invocato ritorna un oggetto Socket
che potrà essere utilizzato per le comunicazioni con il client
- Creare due oggetti
InputStreamReader
eDataOutputStream
per attivare uno stream di comunicazione con il cliente (ovviamente l'InputStreamReader
servirà per leggere le richieste del client, e ilDataOutputStream
per inviare risposte al client):
BufferedReader is = new BufferedReader(new InputStreamReader(client.getInputStream())); DataOutputStream os = new DataOutputStream(client.getOutputStream());
- Richiamare il metodo
close()
sugli oggetti dello stream e sull'oggettoServerSocket
per chiudere i canali di comunicazione:
os.close(); is.close(); server.close();
Per avere informazioni sul server in ascolto, Java mette a disposizione la classe InetAddress
ed i metodi getInetAddress
e getLocalPort
per identificare, rispettivamente, il nome del server e la porta impiegata.
Il metodo getInetAddress
della classe ServerSocket
permette di ottenere un dato che deve essere analizzato dalla classe InetAddress
per poterne ricavare un valore stringa comprensibile. Dunque per conoscere l'indirizzo del server bisogna effettuare
InetAddress indirizzo = server.getInetAddress(); String indirizzo_leggibile = indirizzo.getHostAddress();
Per quanto riguarda il numero della porta utilizzato per ascoltare le chiamate client, bisogna utilizzare il metodo getLocalPort
della classe ServerSocket
in questo modo
int porta = server.getLocalPort();
A livello implementativo, un programma Server deve contenere, dopo una inizializzazione, un ciclo, possibilmente infinito o condizionato da uscita del programma, in cui viene atteso in maniera sincrona il collegamento del client: ad ogni iterazione verrà creato un oggetto Socket
che permetterà di stabilire tale collegamento e gestirà il flusso di dati, ricavabili tramite la DataInputStream
.
Un esempio di programmazione del server è:
static public void start() throws IOException { //inizializzazione dell'oggetto ServerSocket ServerSocket serverFather = new ServerSocket(9999); //recupero info su server InetAddress info = serverFather.getInetAddress(); String server = info.getHostAddress(); int port = serverFather.getLocalPort(); System.out.println("Nome:"+ server + " Porta:"+ port); //ciclo infinito while (true) { System.out.println("Il server va in sleep..."); //accesso le richieste del client Socket socket = serverFather.accept(); System.out.println("Il server si sveglia..."); //trovo le info sul client InetAddress infoclient = socket.getInetAddress(); String client = infoclient.getHostAddress(); int portclient = socket.getLocalPort(); System.out.println("Il client " + client + " " + portclient + " ha svegliato il server..."); //apro il canale di comunicazione con il client DataInputStream is = new DataInputStream(socket.getInputStream()); DataOutputStream os = new DataOutputStream(socket.getOutputStream()); //leggo i dati scritti, l'uscita viene dettata dalla stringa QUIT while (true) { String clientInput = is.readLine(); if ((clientInput == null) || (clientInput.equals("QUIT"))) break; os.writeBytes(clientInput + "\n"); System.out.println("Il client ha scritto " + clientInput); } is.close(); os.close(); socket.close(); System.out.println("Il client è stato soddisfatto...il server torna a dormire..."); } }
Socket Lato Client
modificaA livello client i passaggi sono i seguenti:
- Importare i package
java.io
,java.net
per utilizzare le classiStream
(per i canali di comunicazione) eSocket
(per il nostro scopo) - Intercettare l'eccezione
IOException
che deve essere gestita (tramitetry
ecatch
) o propagata (tramitethrows
), dato che vengono richiamati metodi delle classi che appartengono ai packagejava.io
ejava.net
. - Creare un oggetto
Socket
e specificare l'indirizzo IP ed il numero di porta in ascolto sul server, caratteristiche imposte dal TCP per la comunicazione server/client. Ad esempio, per connettersi al server descritto negli esempi sopra, si deve effettuare un'inizializzazione nel seguente modo:
Socket client = new Socket("localhost",9999);
A livello client l'indirizzo IP viene ricavato mentre la porta viene assegnata in modo dinamico in base alla disponibilità.
- Creare il canale di comunicazione con il server per inviare e ricevere messaggi tramite gli
Stream
diByte
in input ed output tramite le classiDataInputStream
eDataOutputStream
, associandole ai metodigetInputStream
egetOutputStream
della classeSocket
.
DataInputStream is = new DataInputStream(client.getInputStream()); DataOutputStream os = new DataOutputStream(client.getOutputStream());
- Chiudere gli stream di comunicazione e l'oggetto socket
is.close(); os.close(); client.close();
Server Multithreading
modificaNella pratica succede spesso che un server deve poter gestire le richieste di più client (come ad esempio nella richiesta di una pagina web da parte di più browser). Per fare questo è necessario attivare un thread separato per ogni richiesta: si deve pertanto sfruttare la programmazione multithreading messa a disposizione dal Java, effettuando un'estensione della classe Thread
(o, alternativamente, un'implementazione dell'interfaccia Runnable
).
Quello che segue è un esempio di server multithread. Sostanzialmente la tecnica è quella di creare un oggetto che funga da server, e tante sessioni, in thread separati, quante chiamate vengono effettuate dai client.
- Per prima cosa si importano le librerie java.io e java.net
import java.io.*; import java.net.*;
- la classe che gestisce il server sarà un'estensione della classe
Thread
class serverMT extends Thread {
- vengono dichiarate alcune variabili all'interno della classe che verranno utilizzate in seguito
private Socket s; //socket di connessione con il client private BufferedReader in; //stream di input private PrintWriter out; //stream di output private String myclient;
- Il costruttore della classe ha come oggetto il socket del client che effettua la richiesta di connessione al server. Inoltre in questa fase ci si occupa di aprire il canale di comunicazione e di far partire il thread associato alla gestione del servizio
public serverMT(Socket s) throws IOException { this.s = s; in = new BufferedReader(new InputStreamReader(s.getInputStream())); out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())),true); this.start(); }
- Metodo che permette la gestione del servizio, verrà chiamata a seguito di
this.start()
dell'oggetto serverMT:
public void run() { try { myclient = in.readLine(); while (true) { String str = in.readLine(); if (str.equals("END")) break; System.out.println("Ricevuto da C" + myclient + " e rispedito " + str); out.println(str); } System.out.println("chiusura..."); s.close(); } catch(IOException e) { System.out.println("Eccezione"); } }
Note
modifica- ↑ Javadoc della classe INetAddress, su download.oracle.com. URL consultato il 5 giugno 2011.