Server Antonio D'Errico
2148054262 |
|
Corso di Reti
di Calcolatori |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Progetto del Server per
una Chat Aziendale
Il sistema è stato modellato secondo il
pattern Client/Server. Questa parte del progetto si occupa della
realizzazione della parte Server del sistema da interfacciare con il client
ChatD. L’idea che sta alla base
del progetto è quella che un client possa connettersi ad uno qualsiasi dei
server che realizzano la chat conoscendone solo l’indirizzo e la porta
d’ascolto; una volta connesso il client dovrà identificarsi e così potrà
iniziare ad utilizzare la Chat. I server, da parte loro,
sono tutti interconnessi gli uni agli altri in modo da formare una rete nella
quale nessun server è predominante rispetto agli altri e tutti condividono le
stesse informazioni sui gruppi e i client ad essi collegati, in questo modo
si semplifica il protocollo di comunicazione a scapito però di un overhead
nelle connessioni in quanto ogni server è collegato a tutti quelli che
compongono la rete. Inoltre poiché le discussioni sono organizzate secondo
gruppi tematici il server deve gestire tutte le operazioni che dei vari
client possono compiere come: -
inviare
messaggi all’interno del gruppo, -
l’aggiunta
di un gruppo, -
liste
di utenti collegati, -
cambiamento
di gruppo, -
ecc. Si è scelto di non implementare un vero e proprio protocollo
di autenticazione in quanto sarebbe stato necessario l’intervento di una
terza entità che avrebbe dovuto autenticare chi richiede di accedere al
servizio, o che, nel caso di un server, richiede di entrare a far parte della
rete di interconnessione. Comunque la fase di autenticazione è presente nel
protocollo ed implementata in modo lasco, così che l’estensione di questo
possa essere effettuata in modo indolore. Cuore
del progetto è il file StdProtocol che incapsula il protocollo di
comunicazione gestisce le informazioni relative ai gruppi ed ai clienti
connessi smista i messaggi. Poiché
il server deve rimanere in attesa di due tipi di connessione ho creato due
thread che si mettono in attesa rispettivamente di altri server e altri
client e sono ListenServer e ListenClient, che rimangono in attesa
bloccandosi di una connessione e quando la ottengono generano rispettivamente
dei thread di tipo ComServer e ComClient che gestiscono i messaggi e si
occupano di ottenere dall’oggetto StdProtocol le informazioni che i sistemi
remoti richiedono.
Compito
del server è quello di rimanere in attesa di nuove connessioni e gestire i le
azioni dei client collegati e rimanere in contatto se esistono con altri
server. Fase fondamentale, è
svolta dal thread ListenClient, che si occupa di, rimanere in attesa sulla
porta predisposta all’ascolto dei client e generare il thread ComClient che
gestisce la socket, elabora parzialmente i messaggi che riceve, invocando le
corrette procedure che fanno parte del protocollo di comunicazione stabilito
e raccoglie le informazioni sul client. La prima fase di
comunicazione consiste nell’autenticazione e prevede l’invio dell’username e
della password da parte dell’utente, dovrebbe seguire un controllo da parte
del server (non implementato) che, in caso di esito positivo, rende possibile
al client di connettersi alla Chat. Il client appena
connesso entra nel gruppo default che è sempre presente su tutti i server
potrà poi se vuole cambiarlo. La scelta della connessione automatica ad un
gruppo è stata dettata dal fatto che in questo modo al client non vengono
fatti conoscere in anticipo (prima dell’autenticazione) tutti i gruppi presenti
sul sistema anche se ciò ovviamente pone dei forti overhead nella gestione
(al collegamento) del gruppo default. Seguono poi i
messaggi di routine che permettono di
cambiare gruppo, conoscere gli appartenenti ad un gruppo, i gruppi connessi,
inviare messaggi e lasciare la chat in modo “soft”. Le stringhe fornite
dall’utente sono del tipo: <Header><Messaggio> Dove Header appartiene alla seguente lista di comandi validi:
Il server risponde poi a
questi messaggi con i seguenti codici: 201: Ok con inserimento
al gruppo; 202: Ok con rimozione
dal gruppo; 203: Ok login
effettuato; 241: Ok messaggio
pubblico consegnato; 242: Ok messaggio
privato consegnato; 310: Successo parziale
nel login; 430: Fail, fase di
autenticazione; 441: Fail, errore nella consegna
del messaggio pubblico; 442: Fail, errore nella
consegna del messaggio privato; 610: Risposta al comando
LISTGROUPS; 611: Messaggio
automatico di refresh della users window; 612: Messaggio
automatico di refresh della groups window; 632: Risposta al comando
LISTUSERS; 641: Messaggio pubblico
da un utente del gruppo; 642: Messaggio privato
da un utente del gruppo; Di questi messaggi di
risposta alcuni hanno un formato più complesso in quanto riportano delle
rappresentazioni di strutture dati che devono essere fornite all’utente tali
messaggi sono:
Il formato di risposta è
fondamentalmente lo stesso per 610/612 e 611/632 ma cambia ovviamente il modo
di elaborazione da parte del client in quanto risponde messaggi differenti. Se il client, cessa di
esistere o invia il messaggio di QUIT, è automaticamente rimosso da tutte le
strutture dati che il server gestisce ed è considerato disconnesso, tutti i
client del gruppo di appartenenza del client rimosso, ricevono la lista nuova
utenti. Per non appesantire il
sistema non si è andato ne’ a creare un log file nel quale registrare tutte
le operazioni effettuate e ovviamente non si controlla chi è o meno connesso
in quanto ciò rientra nei “compiti” della fase di
autenticazione.
Il server deve rimanere in attesa sia di altri clients sia di altri server in modo che si possa formare la rete per la comunicazione, in teoria un solo server può, dal punto di vista del protocollo, gestire da solo tutti i dati e i clients connessi, ciò ovviamente non è possibile nel mondo reale a causa delle risorse “limitate” che sono presenti sul sistema e quindi per un corretto bilanciamento del carico il protocollo prevede più server che si devono coordinare in modo da mantenere coerenti tutte le informazioni per gestire i clients. Non esiste un server principale ma le informazioni sono distribuite su tutti gli appartenenti alla rete e solo una piccola parte replicata su ognuno in questo modo se un server cessa di funzionare i clients ad esso connessi non sono più visti dagli altri e i server semplicemente cancellano tutte le informazioni a lui relative non preoccupandosi di altro. Anche il protocollo di login presso un altro server è abbastanza semplice, quando il server parte gli vengono fornite le porte di ascolto per i client e per i server l’username e la password, il server crea se possibile le proprie socket e poi legge un file di configurazione dove sono presenti gli IP address e le relative porte di ascolto di altri server noti (tale file potrebbe essere ad ogni sessione aggiornato!) e tenta di connettersi ad essi. Se non trova nessuno in ascolto agli indirizzi noti crea una nuova rete e si mette in ascolto di altri server e client. Nel caso trovi qualcuno in ascolto, si registra presso questo server (anche qui la fase di autenticazione non è stata correttamente implementata in quanto avrebbe per forza richiesto la progettazione di una terza entità riconosciuta ai due che fungesse da arbitro), richiede gli indirizzi di tutti i server attivi in quel momento e si registra anche presso questi, richiede poi la lista dei gruppi attivi e dei relativi utenti connessi e si mette in attesa di connessioni da altri clients e server. Nel caso due server cerchino di entrare a far parte contemporaneamente della rete potrebbero non vedersi con questo tipo di protocollo, una soluzione che si può inserire è quella che prevede uno scambio periodico di messaggi di refresh information in momenti stabiliti, essendo però l’attivazione di un server un’operazione poco frequente ho deciso di non inserire per adesso questo ulteriore tipo di controllo che avrebbe aggiunto un ulteriore overhead. Il protocollo si basa, come già avveniva tra server e client, sullo scambio di messaggi che comportano richiesta di informazioni e servizi. Il formato di richiesta è sostanzialmente il medesimo usato e prevede un messaggio così composto: <Header><Messaggio> dove Header appartiene al seguente insieme
di messaggi validi:
I messaggi di risposta sono i seguenti: 310: Autenticazione parziale, richiesta di invio password, viene fornito in piggybacking il nome del server al quale si è fatta la richiesta 203: Ok, autenticazione avvenuta con successo 632: Lista dei server connessi (fase di learning iniziale) Il formato del messaggio di risposta 632 è il seguente: 632 <IP_address>:<listening_port>
<IP_address>:<listening_port> ...
<IP_address>:<listening_port> è proprio da questo messaggio che segue la fase di autenticazione presso tutti i server e dopo essersi registrato presso gli altri server effetto la richiesta SRVGRPRQST alla quale mi viene risposto con una serie di NWGROUP GRPVAR che mi permettono di costruire il DataBase relativo ai client collegati.
Si è scelto di non implementare alcune funzionalità in quanto ne sarebbe risultato un progetto troppo complesso. Vediamone alcune in dettaglio dando alcune possibili tracce di soluzione. La funzionalità forse
più importante trascurata a livello di implementazione (ma non di
progettazione) è quella che riguarda la questione sicurezza, non sono state
fornite entità software che effettuino di fatto l’autenticazione e si è preferito lasciare al solo
protocollo (che ammette tutti) questo compito senza scrivere file di password
e cose simili che il server avrebbe dovuto leggere e tenere aggiornato. La soluzione che più
sarebbe stata congeniale è quella che prevede un’entità che si occupa solo ed
esclusivamente dell’autenticazione, strutturata a livelli o replicata (in
modo da ridurre i tempi di ripresa del servizio in caso di fail), una sorta
di server Kerberos, che fornisca password valide solo per quella sessione e
gestica in modo automatico i tentativi di accesso multiplo. Altra funzionalità non
implementata è l’estensione dell’interfaccia grafica in modo da permettere
una più facile ed intuitiva configurazione del server, un monitoraggio
particolareggiato per ogni entità connessa e una migliore visualizzazione dei
dati relativi alla situazione attuale. Infine un’ulteriore
miglioria potrebbe essere quella di raffinare il protocollo in modo che si
forniscano più informazioni (ad es. versione client, versione sever, versione
del protocollo, messaggi di configurazione…) e si possano permettere
restrizioni sulla visibilità della rete.
|