Frage

Ich entwerfe ein Spiel-server mit Skripting-Fähigkeiten.Das Allgemeine design wie das geht:

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.

Jetzt kommt der Letzte Teil ist, was die meisten schwierig für mich jetzt.

Derzeit mein design erlaubt mir, für eine Klasse, die erbt Client erstellen Rückrufe zu bestimmten empfangene Ereignisse.Diese Rückrufe sind verwaltet in einer Liste und die empfangenen Puffer durchläuft einen Prozess analysieren jedes mal, wenn etwas empfangen wird.Wenn der Puffer gültig ist, wird der Rückruf aufgerufen wird, wo es wirken auf das, was in den Puffer.Eine Sache zu beachten ist, dass die Rückrufe gehen können, um die scripting-engine, an welcher Stelle nichts sicher ist, was passieren kann.

Jedes mal, wenn ein Rückruf beendet ist, wird die aktuelle Empfangspuffer zurückgesetzt werden etc.Rückrufe haben derzeit keine Möglichkeit der Rückgabe ein Wert, denn wie bereits erwähnt, kann alles passieren.

Was passiert, ist, dass, wenn irgendwo in der callback etwas sagt dieses->disconnect(), möchte ich sofort trennen Sie das Client, entfernen Sie es von der EventManager, und schließlich entfernen Sie es aus dem Server, wo er auch bekommen sollte schließlich zerstört und den freien Speicher.Allerdings habe ich noch einige Codes ausgeführt werden, nachdem der Rückruf beendet ist, in den Client, so kann ich nicht frei Speicher.

Was sollte ich ändern, in die design?Sollte ich einige zeitgesteuerte Ereignis in der Server die Prüfungen, die Clients sind frei, zu zerstören?Würde das erstellen der zusätzliche Aufwand brauche ich nicht?Wäre es noch in Ordnung, nachdem die callback-Oberflächen zu laufen minimalen code auf dem stack (return -1;) oder nicht?

Ich habe keine Ahnung, was zu tun ist, aber ich bin offen für komplette design-Modernisierungen.

Vielen Dank im Voraus.

War es hilfreich?

Lösung

Sie können einen Referenzzähler Zeiger wie boost::shared_ptr<> zur Vereinfachung der Speicherverwaltung.Wenn der manager-client-Liste verwendet shared_ptrs und den code zum aufrufen der Rückrufe erstellt eine lokale Kopie des shared_ptr der Rückruf aufgerufen wird, wird das Objekt am Leben zu bleiben, bis es ist entfernt von dem manager und die callback-Funktion abgeschlossen ist:

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
  }
}

Die Client Objekt wird automatisch gelöscht werden, sobald der Letzte shared_ptr um es den Gültigkeitsbereich verlässt, nicht jedoch vor.So erstellen Sie eine lokale Kopie der shared_ptr bevor eine Funktion aufgerufen sorgt dafür, dass das Objekt nicht gelöscht wird unerwartet beendet.

Andere Tipps

Sollten Sie ein Objekt wie zum Beispiel "Session", die Strecke insbesondere Nachrichtenfluss von Anfang bis Ende (1 client).Dieses Objekt sollte auch darauf achten, zum aktuellen Stand:vor allem die Puffer und Verarbeitung.Jedes Ereignis als Auslöser für einen Rückruf MUSS, aktualisieren Sie den Status der entsprechenden Sitzung.Libevent ist in der Lage, Sie mit jeder Folge der geplanten Veranstaltung:Erfolg, Fehler, timeout.Jede dieser Arten sollte reflektiert werden, mit Ihrer Logik.Im Allgemeinen, wenn die Arbeit mit Ereignissen ist, sollten Sie Ihre Verarbeitungslogik zu werden, ein Automat mit einem Zustand.

http://en.wikipedia.org/wiki/Reactor_pattern kann eine gute Ressource für Ihre Aufgabe.

Lassen Sie den Client::disconnect () - Funktion ein Ereignis senden, um die EventManager (oder Server) Klasse.Dies bedeutet, dass Sie müssen einige Art von event-handling im EventManager (oder Server), ein Ereignis-Schleife Beispiel.

Meine Allgemeine Idee ist, dass Client::disconnect() nicht trennen, der AUFTRAGGEBER unverzüglich, sondern erst, nachdem der Rückruf beendet.Stattdessen ist es nur sendet ein Ereignis an den EventManager (oder Server) Klasse.

Man könnte argumentieren, dass der Client::disconnect () - Methode ist auf der falschen Klasse.Vielleicht sollte es sein-Server::disconnect( Client *c ).Das wäre mehr im Einklang mit der Idee, dass die Server "besitzt" der Client und der Server die Verbindung trennt Clients (und dann einige updates internen Buchhaltung).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top