Architettura Client Server.

Originale

In questa applicazione il server accetta stringhe di messaggi e le restituisce al client dopo aver trasformato tutti i caratteri in maiuscolo.

Si dovrà lanciare in esecuzione prima l'applicazione server, la quale resta in attesa di una richiesta di connessione da qualcuna delle applicazioni client.

Se si tenta di lanciare prima l'applicazione client si otterrà un messaggio di errore perchè nessun server risponderà con l'accettazione ad aprire la connessione.


Avviare NetBeans.

Aggiungere un pannello al frame:

Inserire un componente Label sul pannello. Ridimensionarlo in larghezza, lasciando un piccolo margine di spaziatura con il pannello

Inserire un pulsante con didascalia (proprietà Text): "Ascolta".

Aprire la scheda Source. Prima della definizione della classe, inserire le seguenti righe:

import java.io.IOException;

import java.net.*;

aggiungere il metodo ascolta alla classe:

public void ascolta() throws IOException {

  ServerSocket ascoltatore = new ServerSocket(9898);

  try {

    new Maiuscolo(ascoltatore.accept()).start();

  } finally {

    ascoltatore.close();

  }

}

Completare il gestore dell'evento clic sul pulsante "Ascolta":

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

  // TODO add your handling code here:

  try {

    jLabel1.setText("in ascolto");

    ascolta();

  } catch(IOException e) {

    jLabel1.setText("errore");

  }

}

Il compito del server consiste nel ricevere una stringa di testo, trasformarla in maiuscolo e restituirla al client.

Creare la classe Maiuscolo:

Nella casella Projects, fare clic destro sul nome del package: my.cnvserver e, dal menu contestuale scegliere New → java Class …

Nella casella Class Name scrivere: Maiuscolo. Viene creata la classe. Nell'intestazione del file Maiuscolo.java, aggiungere le seguenti righe:

import java.net.*;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

Completare la dichiarazione della classe derivandola dalla classe Thread:

public class Maiuscolo extends Thread {

All'interno della classe creare un campo privato e il costruttore della classe:

private Socket socket;

public Maiuscolo(Socket socket) {

this.socket = socket;

}

ridefinire il metodo run, che la classe eredita dalla classe Thread:

public void run() {

  try {

    BufferedReader in = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));

    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

    // Invia un messaggio al client per notificargli la connessione.

    out.println("Hello, client.");

    out.println("Per chiudere la connessione invia un messaggio formato solo dal carattere punto\n");

    // Entra in un ciclo in cui legge i messaggi dal client e li restituisce in maiuscolo

    while (true) {

      String input = in.readLine();

      if (input == null || input.equals(".")) {

        break;

      }

    out.println(input.toUpperCase());

    }

  } catch (IOException e) {

    // Segnalazione o gestione dell'errore

  } finally {

    try {

      socket.close();

    } catch (IOException e) {

      // Segnalazione o gestione dell'errore

    }

    // Conferma che la connessione è stata chiusa

  }

}

L'applicazione può essere verificata con telnet, oppure con la seguente applicazione client.

Applicazione Client

Creare un nuovo progetto.

Aggiungere un pannello.

Decidere la disposizione da dare ai seguenti componenti sulla GUI: un pulsante, per chiedere l'apertura della connessione, una casella di testo, per scrivere una stringa di caratteri, ed una Text Area, per mostrare le stringhe ricevute dal server.

Aggiungere un pulsante con didascalia "Connetti".

Aggiungere una casella di testo

Aggiungere un componente multilinea (TextArea).

Passare alla scheda Source. Inserire le seguenti righe prima della dichiarazione della classe:

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.Socket;

Dichiarare i seguenti campi privati della classe:

private BufferedReader in;

private PrintWriter out;

Associare il gestore di evento al pulsante "Connetti":

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

  // TODO add your handling code here:

  try {

    connetti();

  } catch(IOException e) {  }

}

Aggiungere il metodo alla classe:

public void connetti() throws IOException {

  // Crea la connessione e inizia la trasmissione.

  Socket socket = new Socket("127.0.0.1", 9898);

  in = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));

  out = new PrintWriter(socket.getOutputStream(), true);

  // Lettura dei messaggi di conferma inviati dal server

  for (int i = 0; i < 2; i++) {

    jTextArea1.append(in.readLine() + "\n");

  }

}

Tornare alla scheda Design, selezionare la casella di testo e nella finestra delle proprietà associare l'evento "ActionPerformed", corrispondente a premere "invio2 nella casela di testo. Scrivere il gestore dell'evento:

private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {

  // TODO add your handling code here:

  out.println(jTextField1.getText());

  String risposta;

  try {

    risposta = in.readLine();

    if (risposta == null || risposta.equals("")) {

      System.exit(0);

    }

  } catch (IOException ex) {

    risposta = "Errore: " + ex;

  }

  jTextArea1.append(risposta + "\n");

  jTextField1.selectAll();

}