/* * Andrea Caravano (www.andreacaravano.net) * * Esercizio 4: "Linate" * Descrizione: Il recente processo di ristrutturazione dell’aeroporto di Milano Linate, ha causato un * insolito aumento dei passeggeri nell’aeroporto, causando un incremento del numero di hostess e * manager del check-in che, parallelamente, si occupano di modificare i dettagli di un volo in partenza. * Nel problema proposto, le hostess sono rappresentate due Thread che operano solo quando non stanno operando i * due altri Thread assegnati ai manager del check-in. * Si sottolinea, tuttavia, che le hostess e i manager del check-in, possono operare contemporaneamente * tra di loro, gestendo la modifica dei parametri del volo mediante apposite strutture di gestione della mutua esclusione. * I dettagli del volo su cui operano i due gruppi di Thread sono i seguenti: * 1) Località di partenza: Milano Linate * 2) Località di arrivo: Roma Fiumicino * 3) Data e orario del volo: 18/12/2019 – 09:50 * 4) Incremento di un unità del numero di passeggeri (numero iniziale = 0) * Il server inizia la propria attività solo quando tutti e 4 i client sono connessi. * Attraverso un menù di scelta (che includa anche la possibilità di chiusura della connessione), il client decide * quale operazione attuare e lo comunica al server, che si occuperà di fornire opportuna risposta di conferma. * Si suppone non vi siano vincoli di precedenza. Il primo gruppo di processi che viene avviato, da avvio alle * operazioni di modifica. * * Possibile soluzione * Componente Server * * N.B.: L'esercizio scaturisce dalla sola fantasia dell'autore e intende rappresentare una applicazione didattica. * I dettagli in esso contenuti potrebbero non essere corrispondenti alla realtà e intendono valutare le abilità nella gestione delle strutture dati proposte. */ import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.util.Scanner; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Volo { public String localitaPartenza, localitaArrivo, dataVolo; public int numeroPasseggeri; Volo(String localitaPartenza, String localitaArrivo, String dataVolo, int numeroPasseggeri) { this.localitaPartenza = localitaPartenza; this.localitaArrivo = localitaArrivo; this.dataVolo = dataVolo; this.numeroPasseggeri = numeroPasseggeri; } public void stampaInfoVolo() { System.out.println("Informazioni sul volo:"); System.out.format("\tLocalità di partenza: %s%n", localitaPartenza); System.out.format("\tLocalità di arrivo: %s%n", localitaArrivo); System.out.format("\tData del volo: %s%n", dataVolo); System.out.format("\tNumero di passeggeri: %s%n", numeroPasseggeri); } } public class ServerLinate { static final int PORTALISTEN = 9000; static ExecutorService esecutore = Executors.newCachedThreadPool(); static final int TEMPOCONTROLLO = 5000; static final int MINCLIENT = 4; static boolean aspettaClient = true; static int processiAvviati = 0; static CountDownLatch cdlAvvio = new CountDownLatch(1); static Lock mutexManager = new ReentrantLock(); static Lock mutexHostess = new ReentrantLock(); static Semaphore mutex = new Semaphore(1); static Lock mutexVariazioni = new ReentrantLock(); static int processiDentroGruppoManager = 0; static int processiDentroGruppoHostess = 0; static Volo volo = new Volo("Milano Linate", "Roma Fiumicino", "18/12/2019 - 09:50", 0); public static void main(String[] args) { try (ServerSocket procServer = new ServerSocket(PORTALISTEN)) { procServer.setSoTimeout(5000); System.out.format("Processo server avviato con il seguente indirizzo di socket: %s%n", procServer.getLocalSocketAddress()); while (aspettaClient) { try { Socket tempSocket = procServer.accept(); processiAvviati++; if (processiAvviati <= MINCLIENT / 2) { esecutore.execute(() -> { try (Socket varClient = tempSocket) { System.out.format("Thread ID = %d - Indirizzo di socket del client: %s%n", Thread.currentThread().getId(), varClient.getRemoteSocketAddress()); manager(varClient); } catch (IOException e) { System.err.format("Errore di avvio della comunicazione: %s%n", e.getMessage()); } }); } else { esecutore.execute(() -> { try (Socket varClient = tempSocket) { System.out.format("Thread ID = %d - Indirizzo di socket del client: %s%n", Thread.currentThread().getId(), varClient.getRemoteSocketAddress()); hostess(varClient); } catch (IOException e) { System.err.format("Errore di avvio della comunicazione: %s%n", e.getMessage()); } }); } } catch (SocketTimeoutException e) { if (processiAvviati >= MINCLIENT) { aspettaClient = false; cdlAvvio.countDown(); } else { System.err.println("Ancora non è stato raggiunto il numero di client minimo."); } } catch (IOException e) { System.err.format("Errore nella creazione di nuovi socket: %s%n", e.getMessage()); } } } catch (IOException e) { System.err.format("Errore lato server: %s%n", e.getMessage()); } } private static void manager(Socket varClient) { try ( BufferedReader BR = new BufferedReader(new InputStreamReader(varClient.getInputStream(), "UTF-8")); PrintWriter PW = new PrintWriter(new OutputStreamWriter(varClient.getOutputStream(), "UTF-8"), true) ) { cdlAvvio.await(); mutexManager.lock(); try { processiDentroGruppoManager++; if (processiDentroGruppoManager == 1) { mutex.acquire(); } System.out.format("Il manager n. %d ha avviato la propria attività%n", processiDentroGruppoManager); } finally { mutexManager.unlock(); } PW.println("100"); // Tratto da HTTP: "Continue" comunica(BR, PW); mutexManager.lock(); try { processiDentroGruppoManager--; if (processiDentroGruppoManager == 0) { mutex.release(); } } finally { mutexManager.unlock(); } } catch (IOException e) { System.err.format("Errore di I/O: %s%n", e.getMessage()); } catch (InterruptedException e) { System.err.format("Errore di gestione dei meccanismi della programmazione concorrente: %s%n", e.getMessage()); } } private static void hostess(Socket varClient) { try ( BufferedReader BR = new BufferedReader(new InputStreamReader(varClient.getInputStream(), "UTF-8")); PrintWriter PW = new PrintWriter(new OutputStreamWriter(varClient.getOutputStream(), "UTF-8"), true) ) { cdlAvvio.await(); mutexHostess.lock(); try { processiDentroGruppoHostess++; if (processiDentroGruppoHostess == 1) { mutex.acquire(); } System.out.format("La hostess n. %d ha avviato la propria attività%n", processiDentroGruppoHostess); } finally { mutexHostess.unlock(); } PW.println("100"); // Tratto da HTTP: "Continue" comunica(BR, PW); mutexHostess.lock(); try { processiDentroGruppoHostess--; if (processiDentroGruppoHostess == 0) { mutex.release(); } } finally { mutexHostess.unlock(); } } catch (IOException e) { System.err.format("Errore di I/O: %s%n", e.getMessage()); } catch (InterruptedException e) { System.err.format("Errore di gestione dei meccanismi della programmazione concorrente: %s%n", e.getMessage()); } } private static void comunica(BufferedReader BR, PrintWriter PW) throws IOException { int scelta = new Scanner(BR.readLine()).nextInt(); while (true) { if (scelta == 1) { PW.println("100"); mutexVariazioni.lock(); try { volo.localitaPartenza = BR.readLine(); PW.println("200"); // Tratto da HTTP: "OK" } finally { mutexVariazioni.unlock(); } } else if (scelta == 2) { PW.println("100"); mutexVariazioni.lock(); try { volo.localitaArrivo = BR.readLine(); PW.println("200"); } finally { mutexVariazioni.unlock(); } } else if (scelta == 3) { PW.println("100"); mutexVariazioni.lock(); try { volo.dataVolo = BR.readLine(); PW.println("200"); } finally { mutexVariazioni.unlock(); } } else if (scelta == 4) { PW.println("100"); mutexVariazioni.lock(); try { volo.numeroPasseggeri++; PW.println("200"); } finally { mutexVariazioni.unlock(); } } else if (scelta == 5) { PW.println("100"); // Tratto da HTTP: "Continue" PW.println("202"); // Tratto da HTTP: "Accepted" break; } else { PW.println("405"); // Tratto da HTTP: "Method not allowed" } volo.stampaInfoVolo(); PW.println("100"); scelta = new Scanner(BR.readLine()).nextInt(); } } }