Salve a tutti, quest'oggi voglio spiegarvi come creare applicazioni Client-Server in java.

Innanzitutto, cos'è una applicazione Client-Server?

Una applicazione Client-Server è una applicazione che mette in comunicazione due computer attraverso una rete. Applicazioni client server molto famose possono essere eMule, Skype, Msn.

Già, sono tutte applicazioni molto carine ma come fare per crearne una?

 

Beh le classi che ci servono per creare una applicazione del genere sono sostanzialmente 4: ServerSocket, Socket, BufferedReader e DataOutputStream. Andiamo anzitutto a vedere come creare la base della nostra applicazione, colui che ci metterà effettivamente in comunicazione: il Server.

Di norma una applicazione Client-Server mette in comunicazione più Client tra loro, ma finché non viene liberata la connessione che viene stabilita tra Socket e Server il Server non può accettare altre connessioni. In questa guida vedremo anche come risolvere questo problema.

Innanzitutto dobbiamo creare una classe che chiameremo Server. Questa classe estende Thread. Nel metodo run di questo Thread dobbiamo fare semplicemente questo:

1. Creiamo una nuova variabile di tipo ServerSocket, passando nel costruttore la porta sulla quale ci mettiamo in ascolto:

2. Dopo aver creato questa variabile entriamo in un ciclo infinito che si preoccuperà di accettare le nuove connessioni dai Client e di far partire un'altro Thread che operi su di esse.

 

try{
//creiamo un server in ascolto sulla porta 2222
ServerSocket server= new ServerSocket(2222);
//entriamo nel ciclo infinito
while(true){
//controlliamo se ci sono nuove connessioni da parte di un client
//il metodo accept della classe ServerSocket resta in attesa finchè non c'è una connessione, e appena c'è una connessione ritorna la Socket che si è connessa
Socket sock= server.accept();
//ora che abbiamo la socket sulla quale operare la affidiamo a ClientConnection un thread che abbiamo creato noi.
ClientConnection client= new ClientConnection(sock);
//facciamo partire il thread
client.start();
//teniamo traccia della nuova connessione del client aggiungendolo ad una arraylist di ClientConnection, variabile di istanza della classe Server.
this.connessioni.add(client);
}
} catch (IOException ex) {
}

Questo è il metodo run della classe Server. Come spiegato già dai commenti del codice Server avrà come variabile di istanza una ArrayList di ClientConnection. Ma cos'è questo ClientConnection? E' una inner class (definita all'interno della classe Server) che prende in input una Socket, la salva nella sua variabile di istanza e ci lavora su. Andiamo a vedere come creare questa classe.

 

 

private class ClientConnection extends Thread{

//questa è la socket sulla quale andremo a lavorare
private Socket sock;

//questo è il BufferedReader che utilizzerermo per leggere dalla socket.
private BufferedReader reader;

//questo è il DataOutputStream che utilizzeremo per scrivere sulla Socket
private DataOutputStream writer;

//il costruttore prende in input una socket
public ClientConnection(Socket clientSock){
//innanzitutto la salviamo nella variabile di istanza sock.
this.sock=clientSock;
//poi inizializziamo le variabili reader e writer
try {
this.reader = new BufferedReader(new InputStreamReader(this.sock.getInputStream()));
this.writer= new DataOutputStream(this.sock.getOutputStream());
} catch (IOException ex) {
}
}

//a questo punto creiamo due metodi che ci serviranno per scrivere e leggere dalla socket

//questo metodo legge una nuova riga dallo stream, quindi ricordatevi di inserire sempre un \n per inviare qualcosa al Server.
public String readLine(){
String line=null;
try {
line = this.reader.readLine();
} catch (IOException ex) {
}
return line;
}
//quest'altro metodo scrive sulla socket una nuova linea (mette da solo il \n)
public void writeLine(String line){
try {
this.printer.writeBytes(line + "\n");
} catch (IOException ex) {
}
}
}

Ok questa è la nostra innerclass: ma manca qualcosa?? Ah già il metodo run. Il metodo run si diversifica a seconda delle applicazioni che vogliamo creare ma in linea di massima è fatto così:

 

 

public void run(){
String line=null;
//continua il ciclo per sempre ma resta fermo fin quando non arriva un nuovo comando al server
while((line=this.readLine())!=null){
//esegui diverse cose in base al comando passato.
}
}

Già, perchè per colloquiare con il server dovete inviare stringhe come una lina di comando, e questo dovete farlo con una serie di if che vadano a controllare (per esempio) la prima parola prima dello spazio inviata al server.

Ora sta solo alla vostra fantasia creare una serie di comandi che il client deve inviare al vostro server. Ricordate che se volete inviare messaggi a tutti i client lo potete fare, poichè avete l'arraylist di ClientConnection. Quindi se volete inviare un messaggio a tutti basta scorrere tutto l'arraylist e utilizzare il metodo writeLine di ogni clientConnection per scrivere sulla loro socket.

 

Ma vediamo adesso come si deve comportare il Client. Il client deve innanzitutto connettersi al Server, e questo lo facciamo tramite una variabile di tipo Socket:

 

Socket sock= new Socket("locahost", 2222);

In questo modo ci connettiamo al server sulla nostra macchina in ascolto sulla porta 2222. In caso vogliate connettervi ad un server presente su di un'altra macchina al posto di localhost dovrete scrivere l'ip di quella macchina (naturalmente le due macchine devono essere collegate da una rete).

Una volta connessi dovete usare anche qui le classi DataOutputStream e BufferedReader per leggere e scrivere sugli stream della Socket e quindi inviare comandi al server e leggere ciò che il server vi sta inviando.

 

Un'ultima cosa prima di lasciarvi: ho usato la classe DataOutputStream e non il PrintWriter perchè quest'ultimo da dei problemi quando deve essere letto lo stream.

 

Mi auguro di essere stato chiaro e spero che questa guida possa esservi utile. ;)