Pregunta

Estoy diseñando un servidor de juegos con capacidades de scripting. El diseño general es la siguiente:

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.

Ahora, la última parte es lo que es el más difícil para mí ahora.

En la actualidad mi diseño me permite una clase que hereda Client para crear devoluciones de llamada a los eventos recibidos específicos. Estas devoluciones de llamada se gestionan en una lista y la memoria intermedia recibida pasa por un proceso de análisis que se recibe cada vez que algo. Si el buffer es válida, la devolución de llamada se llama donde es actuar sobre lo que está en la memoria intermedia. Una cosa a destacar es que las devoluciones de llamada se pueden bajar al motor de scripting, momento en el que nada es seguro de lo que puede suceder.

Cada vez que termina una devolución de llamada, el búfer de recepción actual tiene que ser reajustada etc. devoluciones de llamada actualmente no tienen la capacidad de devolver un valor, ya que como se ha dicho antes, cualquier cosa puede pasar.

Lo que pasa es que cuando en algún lugar de la devolución de llamada algo dice this-> desconexión (), quiero desconecte inmediatamente el Client, quitarlo de la EventManager, y finalmente eliminarlo de la Server, donde también debe conseguir finalmente destruido y la memoria libre. Sin embargo, todavía tengo algo de código que se ejecuta después de la devolución de llamada termina en el cliente, por lo tanto no puedo liberar memoria.

¿Qué debería cambiar en el diseño? ¿Debo tener algún evento programado en el Server que comprueba la que Clients son libres para destruir? Habría que crear una sobrecarga adicional que no necesito? ¿Seguiría siendo bien después de la devolución de llamada termina de ejecutar código mínimo en la pila (return -1;) o no?

No tengo idea de qué hacer, pero estoy abierto para el diseño completo renueva.

Gracias de antemano.

¿Fue útil?

Solución

Puede utilizar un puntero de referencia contado como boost::shared_ptr<> para simplificar la gestión de memoria. Si la lista de clientes del administrador utiliza shared_ptrs y el código que llama a las devoluciones de llamada crea una copia local de la shared_ptr la devolución de llamada se denomina en adelante, el objeto permanecerá viva hasta que se elimina del gestor de y la función de devolución de llamada es completa:

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

El objeto Client se eliminará automáticamente una vez que la última shared_ptr que se encuentra fuera de su alcance, pero no antes. Por lo tanto la creación de una copia local de la shared_ptr antes de una llamada a la función se asegura de que el objeto no se borra de forma inesperada.

Otros consejos

Debe considerar un objeto como "sesión" que hará un seguimiento particular, el flujo de mensajes de principio a fin (desde el 1 de cliente). Este objeto también debe tener cuidado de estado actual: principalmente los tampones y procesamiento. Cada evento que desencadena una devolución de llamada debe actualizar el estado de la sesión correspondiente. Libevent es capaz de proveerle con cualquier resultado de los eventos programados: el éxito, el fracaso, el tiempo de espera. Cada uno de estos tipos debería reflejarse con su lógica. En general, cuando se trabaja con eventos, considere su lógica de procesamiento para ser un autómata con un estado.

http://en.wikipedia.org/wiki/Reactor_pattern puede ser un buen recursos para su tarea.

Sea la función de cliente :: desconexión () envía un evento al EventManager (o servidor) clase. Esto significa que se necesita algún tipo de manipulación en EventManager (o servidor), un bucle de eventos, por ejemplo evento.

Mi idea general es que el cliente :: desconexión () no permite aislar al cliente de inmediato, pero sólo después de la devolución de llamada terminado de ejecutarse. En su lugar, sólo se publica un evento para EventManager (o servidor) clase.

Se podría argumentar que el método de cliente :: desconexión () está en la clase equivocada. Tal vez debería ser de datos :: desconexión (Cliente * c). Eso sería más en línea con la idea de que el servidor 'posee' el cliente y del servidor que desconecta los clientes (y luego actualiza algunos contabilidad interna).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top