Java/Socket: differenze tra le versioni

Wikibooks, manuali e libri di testo liberi.
Contenuto cancellato Contenuto aggiunto
m SunBot: Cambio (-TCP +TCP)
Riga 1: Riga 1:
Il linguaggio Java tramite l'utilizzo di particolari classi incluse nel suo package nativo permette la gestione del flusso di dati su reti basate sul protocollo [[TCP]]/[[IP]] e [[UDP]]/[[IP]].
Il linguaggio Java tramite l'utilizzo di particolari classi incluse nel suo package nativo permette la gestione del flusso di dati su reti basate sul protocollo [[Transmission Control Protocol|TCP]]/[[IP]] e [[UDP]]/[[IP]].


Per il protocollo TCP si utilizzano le seguenti classi:
Per il protocollo TCP si utilizzano le seguenti classi:

Versione delle 19:09, 9 mar 2006

Il linguaggio Java tramite l'utilizzo di particolari classi incluse nel suo package nativo permette la gestione del flusso di dati su reti basate sul protocollo TCP/IP e UDP/IP.

Per il protocollo TCP si utilizzano le seguenti classi:

  1. InetAddress, per la gestione degli indirizzi IP
  2. ServerSocket, per la creazione di socket lato server
  3. Socket, per la creazione di socket lato client
  4. DatagramSocket, implementa i socket per la trasmissione senza connessione
  5. MulticastSocket, fornisce supporto per i socket di tipo multicast

Indirizzo IP

Nel Java un indirizzo IP è rappresentato dalla classe InetAddress che fonisce tuti i metodi necessari a manipolare un indirizzo internet necessario all'instradamento dei datu sulla rete e consente la trasformazione di un indirizzo nelle sue varie forme:

getAllByName(String host) - è una funzione 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 una stringa rappresentante l'indirizzo IP dell'host nella forma decimale separata da un punto.

getHostName() ritorna una stringa rappresentante il nome dell'host.

Socket Lato Server

Per realizzare un canale di comunicazione Client/Server occorre la crezione di un programma Server che funge da ascolto su una determinata porta e di un programma Client che effettua l'invocazione dello stesso.

Per la creazione del programma Server in Java è necessario seguere i seguenti passaggi:

  1. Importare i package java.io e java.net per poter utilizzare le classi Socket e ServerSocket
  2. Intercettare l'eccezione IOException che deve essere gestita (tramite try & catch) o propagata (tramite throws), dato che vengono richiamati metodi delle classi che appartengono ai package java.io e java.net.
  3. Creare un oggetto ServerSocket, utilizzando il costruttore ServerSocket (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.

  1. Utilizzare il metodo accept() dell'oggetto ServerSocket per poter accettare le chiamate Client su un oggetto Socket
 Socket client = server.accept();

Il metodo che viene invocato ritorna un'oggetto socket che potrà essere utilizzato per le comunicazioni con il client

  1. Creare due oggetti DataInputStream e DataOutputStream per attivare uno stream di comunicazione con il cliente (ovviamente il DataInputStream servirà per leggere le richieste del client, e il DataOutputStream per inviare risposte al client)
 DataInputStream is = new DataInputStream(server.getInputStream());
 DataOutputStream os = new DataOutputStream(server.getOutputStream());
  1. Richiamare il metodo close() sugli oggetti dello stream e sull'oggetto ServerSocket per chiuedere i canali di comunicazione
 os.close();
 is.close();
 server.close();


Per avere informazioni sul server in ascolto java mette a disposizione la classe InetAddress e il metodo getInetAddress, getLocalPort per conoscere il nome del server e la porta. Il metodo della classe ServerSocket getInetAddress permette di ottenere un dato che deve essere analizzato dalla classe InetAddress per poter ritornare un valore string 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 basta utilizzare il metodo getLocalPort della classe ServerSocket in questo modo

 int porta = server.getLocalPort();

A livello di sviluppo l'implementazione corretta di un programma che fa da server prevede, dopo l'inizializzazione del server, un ciclo, possibilmente infinito o condizionato da uscita del programma, di ascolto del client, creando ad ogni ciclo un oggetto socket che permetterà di avere il contatto con il client e gestire la chiamata, tramite la lettura della 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

A livello client i passaggi sono i seguenti:

  1. Importare i package java.io, java.net per utilizzare le classi Stream (per i canali di comunicazione) e Socket (per il nostro scopo)
  2. Intercettare l'eccezione IOException che deve essere gestita (tramite try & catch) o propagata (tramite throws), dato che vengono richiamati metodi delle classi che appartengono ai package java.io e java.net.
  3. 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. A livello server bisogna dunque specificare il suo indirizzo IP o il nome ed inoltre bisogna specificare la porta in ascolto per il server che intende utilizzare. Ad esempio se vogliamo connetterci al server che abbiamo creato prima effettueremo un'inizializzazione del socket 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à .

  1. Creare il canale di comunicazione con il server per inviare e ricevere messaggi tramite gli Stream di Byte in input ed output tramite le classi DataInputStream e DataOutputStream, associandole ai metodi della classe socket getInputStream e getOutputStream.
 DataInputStream is = new DataInputStream(client.getInputStream());
 DataOutputStream os = new DataOutputStream(client.getOutputStream());
  1. Chidere gli stream di comunicazione e l'oggetto socket
 is.close();
 os.close();
 client.close();

Server Multithreading

Nella pratica succede spesso che un server deve poter gestire le richieste di più client (mettiamo ad esempio la richiesta di una pagina web da più browser). Per fare questo bisogna conoscere le basi della programmazione multithreading in java, ed effettuare un'estensione della classe Thread o un'implementazione dell'interfaccia Runnable.

Ecco un modo per creare un server multithread. Sostanzialmente la tecnica si occupa di creare un oggetto server e tante sessioni di server.accept quante chiamate vengono effettuate dai client.

  1. Per prima cosa si importano le librerie java.io e java.net
 import java.io.*;
 import java.net.*;
  1. la classe che gestisce il server sarà un'estensione della classe Thread
 class serverMT extends Thread {
  1. dichiaro alcune variabili all'interno della classe che verrano 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;
  1. il costruttore della classe ha come oggetto il socket del client che effettua la richiesta di connessione al server. Inoltre in qusta fase ci si occupa di aprire il canale di comunicazione e di mandare in run 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();
}
  1. funzione 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");}
}
}