Domanda

Io sono la progettazione di un server di gioco con funzionalità di scripting. Il disegno generale è questa:

Client connects to Server,
Server initializes Client,
Server sends Client to EventManager (separate thread, uses libevent),
EventManager receives receive Event from Client socket,
Client manages what it received via callbacks.

Ora l'ultima parte è ciò che è il più difficile per me, ora.

Al momento il mio progetto mi permette per una classe che eredita Client per creare callback per eventi specifici ricevuti. Questi callback sono gestiti in una lista e il buffer ricevuto passa attraverso un processo di analisi ricevuto ogni volta qualcosa. Se il buffer è valido, il callback viene chiamata in cui è agire su ciò che è nel buffer. Una cosa da notare è che i callback può scendere al motore di script, a quel punto nulla è sicuro di quello che può accadere.

Ogni volta che un callback finiture, la corrente di buffer di ricezione deve essere ripristinata ecc richiamate al momento non hanno alcuna capacità di restituire un valore, perché, come detto prima, tutto può succedere.

Quello che succede è che quando da qualche parte nel callback qualcosa dice this-> disconnect (), voglio staccare immediatamente il Client, rimuoverlo dalla EventManager, ed infine rimuoverlo dal Server, dove ha anche dovrebbe ottenere finalmente distrutto e la memoria libera. Tuttavia, ho ancora un po 'di codice in esecuzione dopo il callback finisce nel client, quindi non posso memoria libera.

Cosa devo cambiare nella progettazione? Dovrei avere qualche evento programmato nel Server che controlla che Clients sono liberi di distruggere? Vorrei che creare ulteriore sovraccarico non ho bisogno? Sarebbe comunque essere a posto dopo la richiamata finisce per eseguire il codice minimo sulla pila (return -1;) o no?

Non ho idea di cosa fare, ma sono aperto per la progettazione completa rinnova.

Grazie in anticipo.

È stato utile?

Soluzione

È possibile utilizzare un puntatore di riferimento contato come boost::shared_ptr<> per semplificare la gestione della memoria. Se lista di clienti del gestore utilizza shared_ptrs e il codice che chiama i callback crea una copia locale del shared_ptr il callback è chiamato, l'oggetto verrà rimanere in vita fino a quando non viene rimosso dal direttore e la funzione di callback è completo:

class EventManager {
  std::vector< boost::shared_ptr<Client> > clients;

  void handle_event(Event &event) {
    // local |handler| pointer keeps object alive until end of function, even
    // if it removes itselfe from |clients|
    boost::shared_ptr<Client> handler = ...;
    handler->process(event);
  }
};

class Client {
  void process(Event &event) {
    manager->disconnect(this);
    // the caller still holds a reference, so the object lives on
  }
}

L'oggetto Client verrà automaticamente eliminato dopo l'ultima shared_ptr ad esso va fuori del campo di applicazione, ma non prima. Quindi la creazione di una copia locale del shared_ptr prima di una chiamata di funzione fa in modo che l'oggetto non viene eliminato in modo imprevisto.

Altri suggerimenti

Si dovrebbe prendere in considerazione che un oggetto come "Session", che terrà traccia particolare il flusso di messaggi dall'inizio alla fine (da 1 client). Questo oggetto dovrebbe anche prendersi cura di stato attuale: in primo luogo i buffer e l'elaborazione. Ogni evento che innesca una richiamata deve aggiornare lo stato della sessione corrispondente. Libevent è in grado di fornire con un risultato di evento in programma: il successo, il fallimento, il timeout. Ognuno di questi tipi dovrebbe riflettersi con la logica. In generale, quando si lavora con gli eventi, considerare la vostra logica di elaborazione di essere un automa con uno stato.

http://en.wikipedia.org/wiki/Reactor_pattern può essere una buona risorse per il tuo compito.

Sia la funzione client :: disconnessione () invia un evento al EventManager (o server) di classe. Ciò significa che è necessario un qualche tipo di manipolazione in EventManager (o Server), un ciclo di eventi, per esempio evento.

La mia idea generale è che client :: disconnessione () non scollega il Cliente immediatamente, ma solo dopo la richiamata terminato l'esecuzione. Invece, invia solo un evento per l'EventManager (o server) di classe.

Si potrebbe sostenere che il metodo client :: disconnect () è in classe sbagliata. Forse dovrebbe essere Server :: disconnessione (Client * c). Che sarebbe più in linea con l'idea che il server 'possiede' il Cliente ed è il server che stacca i clienti (e quindi aggiorna alcuni contabilità interna).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top