Indice - Progetto di Reti di Calcolatori - Fabio Adani e Marco Chiesi
Implementazione

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).

 

Indietro Inizio pagina Avanti
Indice   Fabio Adani e Marco Chiesi