Si vuole realizzare un sistema di prenotazione esami distribuito: il client fa la prenotazione a uno dei tre server intermedi che notificano al client l'iscrizione senza conferma oppure l'impossibilita' di iscrizione; nel primo caso il server chiede conferma al server di facoltà, che può confermare o annullare definitivamente la richiesta; una seconda richiesta del client a uno dei tre server notifica la conferma o l'annullamento dell'iscrizione.
Da notare la scelta di usare Socketstream, dettata dal fatto che si vuole garantire al sistema di prenotazione completa affidabilità di consegna dai pacchetti (uso del protocollo tcp-ip).
1) Almeno uno dei tre server intermedi è sempre attivo;
2) Il server di facoltà non può mai cadere;
3) Non ci sia congestione nel traffico tra i tre server intermedi, in modo che si possano coordinare efficientemente;
4) Le risposte con la conferma definitiva data dal server di facoltà siano veloci in modo da impedire che le tabelle sui server intermedi saturino con nominativi che attendono di essere iscritti con conferma e che quindi impediscono a eventuali altre richieste di essere accettate. L'azione di iscrizione è comunque idempotente e quindi l'utente può chiedere di iscriversi in un secondo momento.
Il cliente ha un interfaccia che permette di inserire username, password e numero dell'appello (da 1 a 5) a cui iscriversi; inviando questi dati ci si connette ad uno dei tre server che risponde dando l'esito dell'iscrizione provvisoria (non confermata).Se il server non è attivo questo viene comunicato all'utente che può riprovare; dato che assumo che in ogni istante ogni server abbia la stessa probabilità di essere attivo la soluzione migliore è sceglierlo in modo random (anche per questioni di load balancing). Se l'iscrizione è effettuata ma senza conferma (il server deve verificarla con la facoltà) il client può di nuovo (con gli stessi dati) connettersi con uno qualsiasi dei server per chiedere la conferma definitiva. Se non c'è conferma viene notificato al client l'annullamento dell'iscrizione. Da notare che se un server non è attivo è l'utente che deve decidere se ritentare la connessione.
Il Client apre la connessione col server e la richiude non appena riceve una risposta. L'interfaccia utente richiede di inserire username, password e numero dell'appello; gli indirizzi dei server vengono inseriti come argomenti quando viene fatto partire il client.
Il server è composto di alcuni thread:
I Thread sono dotati del metodo connetti() per creare le socket necessarie e del metodo closex() per chiuderle. Ogni server apre una socket d'ascolto per accettare le richieste degli altri due server e una socket viene aperta per comunicare col server di facoltà che a sua volta aveva aperto una socket d'ascolto; un'altra socket d'ascolto è aperta per accettare le richieste dei client.
1)Il thread che serve il cliente si occupa di elaborarne le richieste: controllo password, controllo che l'utente non sia già iscritto con conferma o che la sua iscrizione sia già stata annullata dalla facoltà, controllo che la lista non sia già piena. Se i controlli risultano negativi: se siamo sul server con maggiore priorità si procede all'iscrizione senza conferma e ci si collega agli altri due server, se attivi, per comunicarla; se ci sono incongruenze, cioè i server meno prioritari non accettano la prenotazione già accettata dal server più prioritario, la richiesta viene rifiutata e il tutto viene notificato; se il server non è il più prioritario viene prima fatta la verifica della possibilità di iscrizione con l'altro server più prioritario (gli altri due se siamo sul server meno prioritario); poi, se consentito, viene eseguita l'iscrizione senza conferma e comunicata l'iscrizione al/ai server meno prioritario/i (seguendo sempre l'ordine gerarchico). A questo punto ci si connette con il server di facoltà per verificare la possibilità di iscrizione (pagamento tasse universitarie, iscrizione in corso, ecc....): una volta ricevuta la risposta viene aggiornata la tabella del server; se la risposta è positiva l'utente viene iscritto con conferma, altrimenti viene memorizzata la sua esclusione; l'esito è poi comunicato agli altri due server, se presenti.
2)Il thread si occupa di gestire la comunicazione con il server che sta inizializzando mandandogli la lista aggiornata, se è stata cambiata, e accettando le richieste di aggiornamento del server che è connesso con il client. Se poi il suddetto server cade, è poi compito di questo thread farsi carico della richiesta del client e coordinarsi con il server rimanente, se attivo, chiedendo poi conferma al server di facoltà. Il client non riceverà risposta, ma alla successiva connessione potrà sapere se la sua richiesta è stata accettata o rifiutata.
3)Il thread si occupa di far partire il server inizializzando la porta per servire le richieste dei server e connettendosi col server attivo più prioritario per, eventualmente, aggiornare la tabella. Viene poi inizializzata la socket d'ascolto per i client e fatto partire il thread per servire i client.
4)Il thread permette di connettersi con l'altro server per inizializzare la tabella (durante il periodo di inattività la tabella può essere cambiata sugli altri server) e si occupa di lanciare il thread per gestire la richiesta di un altro server.
5)Il thread serve per comunicare con l'altro server la richiesta del cliente (viene dato il placet per l'iscrizione senza conferma oppure no se la lista è già piena, evento verificato tramite la funzione Oknonpiena()).Viene usato nel thread di risposta al client, o in quello di risposta al server se questo cade e ci si fa carico della richiesta del client. Dopo la comunicazione con il server di facoltà la richiesta può essere confermata o annullata definitivamente mediante i metodi conferma() e cancella().
6)Il thread si occupa di connettersi al server di facoltà e di comunicargli la richiesta di conferma della prenotazione; il risultato è dato dal metodo Okpermessi().
La classe Iestudenti è il database che contiene gli username e le password (vedi metodo contiene()),è implementato con la struttura Hashtable e ha il metodo escluso per verificare se un utente è escluso dall'appello e il metodo escludi per escludere un utente dall'iscrizione all'appello; la classe Ieescluso contiene gli username degli utenti che hanno fatto una richiesta che è stata poi annullata (vedi metodo escludi()). L'identificazione del server è data dalla variabile booleana s# (con # variabile da 0a 2) presente nella classe Ietabella.
La classe Ietabella contiene alcuni metodi: presente serve per verificare la presenza dell'utente nel database, nonpiena() restituisce vero se la lista per quell'appello non è piena, aggiornanonconf() iscrive senza conferma l'utente se possibile, altrimenti restituisce falso, autorizzato() controlla se l'utente è autorizzato con conferma o meno, cambiata() ci dice se la lista è cambiata tramite la variabile cambiata controllata dal metodo cambia(), aggiornaconf() iscrive con conferma l'utente, cancella() toglie l'iscrizione di un utente che era stato iscritto provvisoriamente.
Il server è composto di 2 thread:
1)Si occupa di inizializzare la tabella e di eseguire le richieste dei server intermedi: se l'utente è autorizzato viene data conferma, altrimenti viene imposto l'annullamento della prenotazione.
2)Si occupa di inizializzare la socket d'ascolto per i server intermedi e di far partire il thread che serve le richieste dei server intermedi.
Anche qui abbiamo la classe Ietabella con gli username degli utenti autorizzati per ogni appello; la tabella viene inizializzata col metodo costruisci() e viene consultata col metodo presente().
Il progetto è stato testato sulle macchine del Lab3 e non sono stati riscontrati mal funzionamenti particolari, anche quando viene disattivato il server nel momento in cui sta gestendo la richiesta. Il tempo di set-up dei server si aggira intorno ai 15-20 secondi ma non interessa la rete; le prenotazioni (comunicazione client-server e server-server di facoltà) avvengono quasi in tempo reale (circa 1-2 secondi) in modo da soddisfare l'ipotesi 4:infatti prenotazioni contemporanee da parte di più client sono difficili da mettere in pratica. Il sistema continua a funzionare correttamente anche se vengono interrotti 2 server qualsiasi, che poi vengono riattivati in maniera corretta.
La velocità di esecuzione delle prenotazioni e di coordinamento sono imputabili alla presenza della rete locale; in un ambiente internet ci sarebbe il rischio, nel caso di molte richieste contemporanee, di occupazione totale dei posti disponibili sulle tabelle dei server intermedi (prenotazioni non confermate) impedendo la possibilità di altre prenotazioni.