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

Flusso delle informazioni

Essendo NetGame un ambiente distribuito, si desidera che quando un utente compie una certa azione questa si manifesti su tutta la rete, cioè è necessario che la informazione generata dall'utente sia trasmessa a tutti gli altri client che sono connessi alla rete. Perchè ciò sia possibile, l'informazione deve attraversare vari stadi prima di arrivare a destinazione. Si analizza quindi ora il percorso che devono seguire queste informazione. Come esempio di azione si prenda l'invio di un messaggio pubblico di chat, cioè un messaggio inviato da un utente che sarà visibile a tutte le persone che si trovano nella stessa stanza di colui che l'ha inviato (eventualmente anche su server diversi).

Il punto di partenza è chiaramente l'utente che agendo sull'interfaccia grafica del suo client (MainClientUI) dà il comando di invio del messaggio. L'interfaccia grafica quindi cattura tale evento e comunica al client di chat (RoomClient) che è stato generato un messaggio pubblico. Quest'ultimo a sua volta comunicherà l'azione al nodo server per mezzo dell'agente che si occupa delle comunicazioni (ClientAgent). Dal ClientAgent l'informazione viene passata al server di stanza (RoomServer) che deve provvedere a ritrasmettere a tutti il messaggio che ha appena ricevuto. Deve quindi inviare il messaggio a tutti gli altri utenti che sono sulla rete. Chiaramente, al fine di ridurre il traffico in rete, il RoomServer non comunica direttamente con tutti gli utenti della rete, ma soltanto con gli utenti locali connessi al suo nodo. Inoltre comunica con i tutti i RoomServer remoti analoghi ad esso (ovvero relativi allo stesso gioco), e saranno poi questi ultimi ad avvisare i loro rispettivi clienti. La comunicazione tra il server di stanza ed il client avviene ancora una volta tramite il ClientAgent. Una volta che il client riceve il messaggio, questo provvede ad aggiornare l'interfaccia grafica rendendo l'azione compiuta visibile all'utente. In questo modo il ciclo si richiude. Va evidenziato il fatto che anche l'utente che ha inviato il messaggio viene trattato al pari di tutti gli altri, ovvero l'aggiormento della sua interfaccia grafica avverrà soltanto dopo tutti i passaggi appena visti. Questo in un primo momento potrebbe sembrare una complicazione inutile, ma è invece necessaria in quanto ci sono anche azioni che potrebbero fallire, per cui si deve attendere la risposta dal server prima di poter aggiornare lo stato del client (si vedano le possibili operazioni in conflitto).

Introduzione degli eventi

Il precedente sistema di comunicazione presenta un paio di inconvenienti:

  • Il processo che si occupa di gestire gli eventi legati all'interfaccia grafica è costretto ad attendere la risposta da parte del server ed in questo modo l'interfaccia grafica rimane bloccata.
  • Il server di stanza comunica in modo sequenziale con tutti i suoi clienti e con i server remoti, e quindi ogni comunicazione deve attendere il termine di quella precedente, con un notevole rallentamento.

Per risolvere questi problemi è quindi necessario disaccoppiare le attività, cioè fare in modo che sia possibile eseguire più azioni contemporaneamente. Questo può essere fatto adottando una programmazione basata sugli eventi, in cui ci sono diversi gestori di eventi che sono in esecuzione contemporaneamente. Un gestore di eventi (EventHandler) è quindi un processo a cui è associata una coda di eventi. Il gestore rimane in attesa che qualche altro processo metta nella sua coda un evento per poi prelevarlo ed eseguirlo. Naturalmente l'esecuzione dell'operazione dipenderà dal tipo di evento e di seguito si vedrà una descrizione dei diversi tipi di evento presenti nell'ambiente NetGame.

Con questa tecnica quindi alcuni componenti del sistema visti in precedenza divengono a tutti gli effetti dei gestori di eventi. Ad esempio, il RoomClient ha una coda in cui gli eventi vengono aggiunti dalle routine del framework che gestisce l'interfaccia grafica. Un caso particolare è costituito dal RoomServer in cui non c'è una sola coda di eventi, ma due distinte. Questo perchè il compito del RoomServer è quello di ritrasmettere il messaggio a tutti i suoi client ed a tutti server remoti. La gestione degli eventi in questo caso quindi consiste semplicemente nel prendere un messaggio dalla coda e ridistribuirlo mettendolo nelle code di tutti i ClientAgent e RoomServerAgent, i quali provvederanno a gestire tale messaggio e ad effettuare la realtiva chiamata remota. A tal fine si è quindi prevista la creazione di una classe apposita per la distribuzione degli eventi EventDispatcher che specializza la più generica EventHandler.

La trattazione fin qui fatta fa riferimento alla comunicazione tra RoomClient e RoomServer (e viceversa), ma in maniera del tutto analogo si può considerare la comunicazione tra MainClient e MainServer.

Classificazione degli eventi

Una volta chiarita la necessità di una gestione ad eventi delle comunicazioni tra le varie parti del sistema, si vede ora quali sono i possibili eventi che possono essere generati. Una prima distinzione va fatta tra eventi generati da utenti (UserEvent) ed eventi generati dai server (ServerEvent).

Eventi generati dai client

Gli eventi generati dai client possono essere suddivisi in quattro categorie, riguardanti:

  • Ingresso e uscita dal sistema (LogEvent)
  • Gestione delle partite (MatchEvent)
  • Scambio di messaggi (MessageEvent)
  • Ingresso e uscita da una stanza (RoomEvent)
LogEvent LoginEvent Ingresso di un utente nel sistema
LogoutEvent Uscita di un utente dal sistema
MatchEvent CreateMatchEvent Creazione di una nuova partita
DeleteMatchEvent Eliminazione di una partita
EnterMatchEvent Ingresso in una partita
ExitMatchEvent Uscita da una partita
FinishMatchEvent Terminazione di una partita
StartMatchEvent Avvio di una partita
MessageEvent PrivateMessageEvent Invio di un messaggio privato ad un altro utente
PublicMessageEvent Invio di un messaggio pubblico nella stanza
RoomEvent JoinRoomEvent Ingresso di un utente in una stanza
LeaveRoomEvent Uscita di un utente da una stanza

Eventi generati dai server

Gli eventi generati dal server sono sostanzialmente legati alle problematiche di sincronizzazione discusse in precedenza, ed in particolare alla realizzazione del protocollo 2PC. Oltre a questo, anche la gestione dei guasti viene fatta ad eventi. Alla luce di tutto ciò possiamo distinguere vari tipi di eventi:

  • Realizzazione del 2PC a livello di MainServer (MainServerEvent)
  • Realizzazione del 2PC a livello di RoomServer (RoomServerEvent)
  • Realizzazione del 2PC per la gestione della partite (MatchEvent)
  • Realizzazione del 2PC per il login degli utenti (LogEvent
  • Disconnessione di un server (ServerDisconnectedEvent)
  • Disconnessione di un client (ClientDisconnectedEvent)
MainServerEvent AbortConnectEvent Connessione di un server (II^ fase - insuccesso)
ConnectEvent Connessione di un server (II^ fase - successo)
PrepareConnectEvent Connessione di un server (I^ fase)
RoomServerEvent AbortConnectRoomEvent Connessione di un server (II^ fase - insuccesso)
ConnectRoomEvent Connessione di un server (II^ fase - successo)
PrepareConnectRoomEvent Connessione di un server (I^ fase)
MatchEvent AbortCreateMatchEvent Creazione di una partita (II^ fase - insuccesso)
AbortEnterMatchEvent Ingresso in una partita (II^ fase - insuccesso)
AbortExitMatchEvent Uscita da una partita (II^ fase - insuccesso)
AbortStartMatchEvent Avvio di una partita (II^ fase - insuccesso)
PrepareCreateMatchEvent Creazione di una partita (I^ fase)
PrepareEnterMatchEvent Ingresso in una partita (I^ fase )
PrepareExitMatchEvent Uscita da una partita (I^ fase)
PrepareStartMatchEvent Avvio di una partita (I^ fase)
LogEvent AbortLoginEvent Ingresso di un utente (II^ fase - insuccesso)
PrepareLoginEvent Ingresso di un utente (I^ fase)
Eventi di disconnessione ServerDisconnectedEvent Rilevata disconnessione di un MainServer
ClientDisconnectedEvent Rilevata disconnessione di un client

N.B. Per alcuni eventi del protocollo 2PC riguardanti la seconda fase in caso di successo si sono usati gli stessi eventi riportati nella tabella precedente. Ad esempio: LoginEvent, CreateMatchEvent, ecc.

Indietro Inizio pagina Avanti
Indice   Fabio Adani e Marco Chiesi