MainServer
La classe MainServer rappresenta
il server principale dell'ambiente di NetGame ed ha l'importante compito
di coordinare l'interazione tra le diverse parti del sistema. In particolare
dovrà essere in grado di comunicare con i client connessi alla
rete (sia a livello locale che remoto), con gli altri MainServer
che fanno parte della rete e con i RoomServer presenti
sul suo nodo.
Analizziamo ora le strutture dati memorizzate
a livello di MainServer :
Hashtable localUsers; |
Tabella contenente gli utenti connessi al server corrente. Ogni
entry è costituita dal nickname dell'utente e dal riferimento
al relativo ClientAgent |
Hashtable remoteUsers; |
Tabella contenente gli utenti connessi tramite altri server. Ogni
entry è costituita dal nickname dell'utente e dall'URL del
server a cui è connesso. |
Hashtable remoteServers; |
Tabella dei MainServer remoti. Ogni entry è costituita dall'URL
del server e dal riferimento al relativo ServerAgent . |
Hashtable roomServers; |
Tabella dei RoomServer locali. Ogni entry è costituita dal
nome del gioco e dal riferimento al relativo server di stanza. |
L'utilità di fare distinzione tra utenti
locali ed utenti remoti è dovuta al fatto che si vuole minimizzare
le comunicazioni remote tra un server e l'altro. Infatti ogni server
comunicherà direttamente soltanto con i suoi utenti locali, mentre
per comunicare con utenti remoti, lo farà attraverso il rispettivo
server. Questo giustifica il fatto che la tabella remoteUsers ,
associa ad ogni utente remoto l'indirizzo del server a cui è
connesso. In questo modo sarà possibile comunicare con uno specifico
utente remoto (si prenda come esempio l'invio di un messaggio privato
di chat).
Accanto alle precedenti strutture dati, vanno
aggiunte ulteriori tabelle necessarie per la realizzazione del protocollo
2PC a livello di MainServer :
Hashtable loggingUsers; |
Tabella contenente gli utenti in fase di connessione. Ogni entry
è costituita dal nickname dell'utente e dall'URL del server
a cui si sta connettendo. |
Hashtable connectingServers; |
Tabella contenente i server in fase di connessione. Ogni entry
è costituita dall'URL del server e da un riferimento remoto
ad esso. |
In realtà la tabella connectingServers
può contenere al più una entry per volta.
Un'ulteriore tabella poi
contiene le informazioni relative ai vari giochi disponibili, le quali
sono inviate ai client al momento del loro ingresso nel sistema. A tal
fine è stata creata una classe GameInfo , che contiene,
per ogni gioco, nome, versione, autore, numero minimo e massimo di giocatori,
dimensione in kb del file.
Hashtable gameInfos; |
Tabella contenente informazioni sui giochi. Ogni entry è
costituita dal nome del gioco e dalla relativa classe GameInfo . |
Oltre alle precedenti tabella, a livello di MainServer
sono memorizzate altre variabili, tra cui:
IUserDBAccess userDBAccess; |
Interfaccia di comunicazione con il server di autenticazione
degli utenti |
FileServer fileServer; |
Server per il download dei giochi |
IMainServerUI ui; |
Riferimento all'interfaccia grafica |
Vi sono inoltre diversi parametri di configurazione
del server
ServerInfo localServer; |
Informazioni sul server locale |
ServerInfo remoteServer; |
Informazioni sul server remoto a cui connettersi |
ServerInfo userDBServer; |
Informazioni sul server di gestione degli utenti |
boolean logEnabled; |
Flag che indica se visualizzare i messaggi di log |
boolean authenticationEnabled; |
Flag che indica se è richiesta l'autenticazione degli utenti |
boolean connectionEnabled; |
Flag che indica se è richiesta la connessione ad un altro server |
I parametri di configurazione possono essere
impostati tramite un apposito file di configurazione oppure direttamente
dall'interfaccia grafica. Per motivi di efficienza si è comunque
previsto che la classe MainServer possa essere eseguita
anche senza interfaccia utente, nel qual caso ovviamente la configurazione
sarà possibile soltanto tramite file di configurazione.
La classe ServerInfo serve in pratica
per specificare l'indirizzo di un oggetto remoto tramite nome dell'host,
nome dell'oggetto remoto e porta di comunicazione dell'RMI.
Inoltre il MainServer ha un gestore
di eventi interno (MainServerEventHandler ) che ha il compito
di gestire eventi provenienti dall'interfaccia grafica (attivazione
e disattivazione del server) ed eventi relativi a rilevate disconnessioni
di client o server. Oltre a questo è presente anche un EventDispatcher
che ha il compito di distribuire eventi (login e logout) ai vari ServerAgent
in modo da realizzare il protocollo 2PC. Per maggiori dettagli sull'implementazione
di questo protocollo si veda la classe RoomServer .
Interfacce implementate
Questa classe implementa sia l'interfaccia IServerAccess
(fornisce servizi a server remoti) che IClientAccess (fornisce
servizi ai client).
L'interfaccia IClientAccess presenta
due metodi:
IClientAgent login(String userName, String
password, IMainClient mainClient, IRoomClient roomClient);
void logout(String userName) throws RemoteException;
Questi danno la possibilità agli utenti
rispettivamente di entrare ed uscire nel sistema. Al momento dell'ingresso
il server crea un nuovo oggetto ClientAgent per gestire
la comunicazione con il client. A tal proposito si veda l'implementazione
della classe ClientAgent .
L'interfaccia IServerAccess presenta
invece i seguenti metodi:
public ServerState addServer(String address,
IServerAccess sa) throws RemoteException, FailedConnectionException;
public boolean prepareConnect(String address, IServerAccess sa) throws
RemoteException;
public void commitConnect(String address) throws RemoteException;
public void abortConnect(String address) throws RemoteException;
public void removeServer(String address) throws RemoteException;
public boolean prepareLogin(String user, String url) throws RemoteException;
public void abortLogin(String user, String url) throws RemoteException;
public void remoteLogin(String userName, String address) throws RemoteException;
public void remoteLogout(String userName) throws RemoteException;
public String getAddress() throws RemoteException;
public String getHostAddress() throws RemoteException;
public Hashtable getGameList() throws RemoteException;
Il significato di questi metodi è
già stato chiarito quando si è parlato dell'interazione
server-server, e
della realizzazione del protocollo
2PC applicato a NetGame. La classe ServerState
restituita dal metodo addServer() serve per rappresentare
lo stato di un server ed in pratica comprende le tabelle users ,
loggingUsers , servers e connectingServers .
Avvio di un server
Quando un MainServer viene avviato,
viene eseguita una sequenza di operazioni:
- Si carica la configurazione dal file specificato all'avvio
- Se si esegue con l'interfaccia grafica, viene creata e resa visibile
la finestra per la gestione del server
- Altrimenti il client viene subito avviato tramite il metodo
startServer
Nel caso dell'interfaccia grafica, invece, il
metodo startServer verrà invocato solo quando l'amministratore
del server darà il comando di avvio, dopo avere eventualmente
impostato i parametri di configurazione.
Il metodo startServer a sua volta
compie le seguenti operazioni:
- Invoca il metodo
connectUserDBServer() per connettersi
al server di autenticazione degli utenti (questo accade solo se la
variabile authenticationEnabled è stata impostata
a true ).
- Invoca il metodo
connectRemoteServer() per connettersi
ad un server remoto ed entrare quindi nella rete (questo accade solo
se la variabile connectionEnabled è stata impostata
a true ). Il protocollo 2PC previsto per l'ingresso di
un server è realizzato dal server a cui ci si sta connettendo.
Al termine di questa operazione, il server risulta a tutti gli effetti
come facente parte della rete, anche se ancora non in grado di accettare
connessioni da parte degli utenti.
- Invoca
loadGames() che provvede ad istanziare ed inizializzare
i server di stanza. All'interno di questo metodo vengono anche effettuate
le connessioni tra i RoomServer locali e quelli analoghi
remoti.
- Invoca
registerLocalServer() che registra il server
sull'RMIregistry. Da questo momento in poi il server è attivo
e può accettare connessioni da parte degli utenti.
Nel caso si verifichino errori durante questa
fase di inizializzazione del server, sarà chiaramente necessario
disfare le operazioni già compiute. Ad esempio, se fallisce la
registerLocalServer() sarà necessario disconnettere
il MainServer e tutti i RoomServer da quelli
remoti.
Quando il server viene disattivato (metodo shutdown ),
in pratica si eseguono le operazioni contrarie alle precedenti ed in
ordine inverso ed in più si resettano le strutture dati già
citate (metodo resetServer ).
Gestione dei file di configurazione
Come si è detto, per il funzionamento
ci sono diversi parametri che possono essere configurati, e questi possono
essere memorizzati in un apposito file di configurazione che di default
si chiama netgame.server.properties . Per utilizzare tali
file la classe MainServer è stata dotata di due
metodi, rispettivamente per caricare e salvare una configurazione:
void loadConfig(String filename);
void saveConfig(String filename);
All'interno di questi metodi si fa uso della
classe Properties di Java che permette appunto di caricare
e salvare il valore di una serie di variabili in un file in modo molto
semplice.
Interfaccia grafica
L'interfaccia grafica del server (MainServerUI )
è stata creata estendendo la classe JFrame della
libreria swing di Java. L'interfaccia è composta da un menu a
tendina, da una barra degli strumenti, da un pannello centrale e da
una barra di stato. Il menu a tendina (JMenuBar ) e la barra
degli strumenti (JToolbar ) danno all'utente la possibilità
di compiere operazioni come attivazione e disattivazione del server,
uscita dal programma, caricamento e salvataggio di una configurazione,
visualizzazione informazioni. Nella barra di stato invece compare invece
lo stato attuale del server (ON oppure OFF) ed un messaggio relativo
alle attività svolte correntemente dal server.
Nel pannello centrale invece è possibile
visualizzare quattro ulteriori pannelli distinti, per mezzo di un JTabbedPane :
- Server: Pannello di configurazione dei paratri di connessione
del server lista dei server connessi alla rete
- Utenti: Lista degli utenti locali e remoti connessi al sistema
- Log: Registrazione di tutti le attività effettuate
del server (il log può essere abilitato e disabilitato)
- Giochi: Lista dei giochi installati sul server e relativo
box di informazioni per ogni gioco
Di seguito si riportano alcune immagini che mostrano l'aspetto dell'interfaccia
utente (cliccare sulle immagini per vedere la versione ingrandita).
|