Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli


Programmazione Concorrente e Distribuita: Guida all'Implementazione - Prof. Coen Porisini, Appunti di Elementi di Informatica

Una panoramica sull'implementazione della programmazione concorrente e distribuita, focalizzandosi sui ruoli di server e client. Esplora la gestione delle connessioni tramite socket e l'uso della classe connectionhandler per gestire la comunicazione. Vengono presentati esempi pratici di reader e writer distribuiti, con particolare attenzione alla gestione multi-thread per consentire connessioni multiple. Il documento include anche esempi di codice per la generazione di client e la gestione della comunicazione, offrendo una guida completa per lo sviluppo di applicazioni concorrenti e distribuite.

Tipologia: Appunti

2024/2025

In vendita dal 15/11/2025

AriBab
AriBab 🇮🇹

88 documenti

1 / 16

Toggle sidebar

Questa pagina non è visibile nell’anteprima

Non perderti parti importanti!

bg1
Programmazione concorrente e distribuita
26/03/2025
In entrambi gli esempi abbiamo identificato due ruoli distinti:
Server, il processo che accetta le richieste di connessione;
Client, il processo che effettua le richieste di connessione;
Tuttavia una volta attivata la connessione sono possibili anche schemi differenti (Peer To
Peer).
Architettura Server
è buona norma suddividere il server in due parti:
Una classe che gestisce la richiesta di connessione (Server);
Una classe che gestisce la comunicazione vera e propria (ConnectionHendler);
La classe Server
è quella che istanzia il ServerSocker, si mette in ascolto della richiesta (metodo accept() ).
Una volta che la connessione è stabilita:
istanzia un oggetto della classe ConnectionHandler, passandogli il Socket;
Invoca il metodo void esegui() di connectionHandler per . gestire la comunicazione
public class Server {
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff

Anteprima parziale del testo

Scarica Programmazione Concorrente e Distribuita: Guida all'Implementazione - Prof. Coen Porisini e più Appunti in PDF di Elementi di Informatica solo su Docsity!

Programmazione concorrente e distribuita

In entrambi gli esempi abbiamo identificato due ruoli distinti:

  • Server , il processo che accetta le richieste di connessione;
  • Client , il processo che effettua le richieste di connessione;

Tuttavia una volta attivata la connessione sono possibili anche schemi differenti (Peer To

Peer).

Architettura Server

è buona norma suddividere il server in due parti:

  • Una classe che gestisce la richiesta di connessione (Server);
  • Una classe che gestisce la comunicazione vera e propria (ConnectionHendler);

La classe Server

è quella che istanzia il ServerSocker, si mette in ascolto della richiesta (metodo accept() ).

Una volta che la connessione è stabilita:

  • istanzia un oggetto della classe ConnectionHandler, passandogli il Socket;
  • Invoca il metodo void esegui() di connectionHandler per. gestire la comunicazione public class Server {

public static final int PORT = …; public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(PORT); try { Socket s = server.accept(); try { ConnectionHandler c=new ConnectionHandler(s); c.esegui(); } finally {s.close();} } finally {server.close();} } } La classe ConnectionHandler

Possiede una struttura dati:

  • Per gestire la comunicazione;
  • Per svolgere il compito richiesto dal client;

Possiede due metodi:

  • Il costruttore che istanzia gli stream;
  • Il metodo void esegui() che gestisce la comunicazione; Reader e Writer distribuiti

Un programma legge un file di testo lo invia ad un server che ricerca la presena di un

determinato vocabili all'interno del testo ricevuto.

Il server restituisce il testo privato delle linee in cui compare il vocabolo.

public ConnectionHandler(Socket s, String str) throws IOException { fromClient = new BufferedReader( new InputStreamReader(s.getInputStream())); toClient = new PrintWriter( new OutputStreamWriter(s.getOutputStream())); vocabolo = str; } public void esegui() { try { String str; while((str = fromClient.readLine()) != null) { if(str.contains(vocabolo)) toClient.println(""); else toClient.println(str); toClient.flush(); } fromClient.close(); toClient.close(); } catch (IOException e) {e.printStackTrace();} } } Lato client

Non viene modificato nulla

Lato server

La struttura del lato server è più complessa tuttavia è in grado di gestire la comunicazione solo

con un unico client.

In generale i server devono essere in grafo di gestire più clinet.

è necessario che il server sia un programma con più thread di esecuzione.

La suddivisione in due parti del lato server permette di passare allo sviluppo di un server multi-

thread

Server multi-thread

è possibile costruire un server multi-thread utilizzando:

  • 1 thread per accettare le richieste di connessione;
  • N thread per gestire la comunicazione con n client;

Nota

Posso avere tanti thread quanti sono i client con la quale voglio comunicare.

Da un punto di vista dell'architettura non cambia nulla, ma è necessario che la classe Server che

gestisce le connessioni sia in grado di accettare più connesioni (metodo accept() deve stare

all'interno di un ciclo while)

Gli oggetti della classe ConnectionHandler che gestiscono la comunicazione siano attivi.

Classe Server

Istanzia il ServerSocker.

Utilizza un ciclo infinito in cui all'interno:

  • Si mette in ascolto della richiesta (accept());
  • Una volta che la connessione è stabilita:
  • Il costruttore che istanzia gli stream;
  • Il metodo void run() che gestisce la comunicazione; Reader e Writer distribuiti

Un insieme di programmi leggono de file di testo e li inviano ad un server che ricerca la presenza

di un determinato ocabolo all'interno del testo.

Il server restituisce ad ogni client il testo provato delle linee in cui compare i vocabolo.

Server public class Server { public static final int port = 10001; public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Uso: Server "); System.exit(-1); } ServerSocket server = new ServerSocket(port); try { while(true){ Socket s = server.accept(); ConnectionHandler c = new ConnectionHandler(s,args[0]); c.start(); } } finally {server.close();} } } public class ConnectionHandler extends Thread{ private String vocabolo;

private Socket myS; private BufferedReader fromClient; private PrintWriter toClient; public ConnectionHandler(Socket s, String str) throws IOException { myS = s; fromClient = new BufferedReader( new InputStreamReader(s.getInputStream())); toClient = new PrintWriter( new OutputStreamWriter(s.getOutputStream())); vocabolo = str; } public void run() { try { String str; while((str = fromClient.readLine()) != null) { if(str.contains(vocabolo)) toClient.println(""); else toClient.println(str); toClient.flush(); } fromClient.close(); toClient.close(); myS.close(); } catch (IOException e) {e.printStackTrace();} } }

Osservazioni

Il server multi-thread conesente a più client di connettersi contemporanemanete:

  • Può essere utile contare quanti client sono collegati;
  • Eventualmente ipotizzare un numero massimo di collegamenti.

ConnectionHandler c = new ConnectionHandler(s,args[0],num); c.start(); } else Thread.sleep(100); } finally {server.close();} } } ConnectionHandler public class ConnectionHandler extends Thread{ private String vocabolo; private Socket myS; private BufferedReader fromClient; private PrintWriter toClient; private Contatore c; public ConnectionHandler(Socket s, String str, Contatore n) throws IOException { myS = s; c = n; fromClient = new BufferedReader( new InputStreamReader(s.getInputStream())); toClient = new PrintWriter( new OutputStreamWriter(s.getOutputStream())); vocabolo = str; } public void run() { try { String str; while((str = fromClient.readLine()) != null) { if(str.contains(vocabolo)) toClient.println(""); else toClient.println(str); toClient.flush(); } fromClient.close(); toClient.close();

myS.close(); } catch (IOException e) {e.printStackTrace();} finally {c.dec(); System.err.println(c.val();} } } Generare i clinet

Per generare i clinet in ambiente di prova costruiamo un programma che istanzia numerosi client

(Genera client)

public class generaClient { public static void main(String[] args) throws InterruptedException { if(args.length != 1) { System.err.println("Uso: Client "); System.exit(-1); } for (int i=0; i<20; i++) { Client c = new Client(args[0]); c.start(); Thread.sleep(100); } } }

I client risiedono sulla stessa macchina (Condividono la stdout). è necessario assicurare che

l'utilizzo del canale di uscita avvenga in modo Thread Safe

public class Client extends Thread{ private static final String host = "localhost"; private File f;

Al termine della sequenza il Server stamperà la somma dei valori:

  • È necessario introdurre un gestore della comunicazione:

◦ ConnectionHandler;

Leggi: Il programma che legge

1. Istanzia il ServerSocket:

A. Si predispone all'ascolto su una determinata porta;

2. Si pone all'ascolto e quando arriva una richiesta:

A. Istanzia l'oggetto Socket;

B. istanzia il ConnectionHandler;

C. Attiva il ConnectionHandler;

Leggi import java.io.; //il package di io import java.net.; //il package di rete public class Leggi { public static final int port = 10001; public static void main(String[] args) throws IOException { // 1. Istanzia il ServeSocket ServerSocket server = new ServerSocket(port); try { // 2. Si pone all'ascolto while(true) { Socket s = server.accept(); ConnectionHandler c = new ConnectionHandler(s); c.start(); }

finally {server.close();} } } ConnectionHandler

1. Apre il DataInputStream associato al Socker da cui legge;

2. leggel'ID del Client;

3. legge un nuemro dallo stream e lo somma fino a che non incontra EOS;

4. Stampa su stdout ID e somma;

5. Chiude lo stream e il Socket;

import java.io.; import java.net.; public class ConnectionHandler extends Thread { private Socket sIn; private DataInputStream dIn; private int clientID, somma; public ConnectionHandler(Socket s) throws IOException { dIn = new DataInputStream(s.getInputStream()); sIn = s; } public void run() { try { clientID = dIn.readInt(); //Legge ID Client while(true) //ripeti all'infinito try { somma += dIn.readInt(); //se eos viene sollevata //EOFException } catch (EOFException e) { break; //esci dal ciclo } System.out.println("Client: "+clientID +

for(int i=1; i<11; i++) { int num = rG.nextInt(MAX); System.out.println("Generato numero casuale "+ i +". Si tratta di " + num); dOut.writeInt(num); Thread.sleep(1000); } dOut.close(); s.close(); } } Osservazione

Per permettere un funzionamento adeguato è stato necessario far si che i Clinet inviassero per

prima cosa il proprio ID.

La comunicazine è stata più complessa.

Bisogna trovare un modo per descriverla prima di iniziare a sviluppare il codice.

  • è un aspetto da affrontare durante la fase di progettazione.