Pergunta

Eu estou projetando um servidor de jogos com recursos de script. A concepção geral é a seguinte:

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.

Agora, a última parte é o que é o mais complicado para mim agora.

Atualmente o meu projeto permite-me para uma classe que herda Client para criar retornos de chamada para eventos específicos recebido. Esses retornos de chamada são geridos de uma lista e o buffer recebido passa por um processo de análise cada vez que algo é recebido. Se o buffer é válido, o retorno de chamada é chamado de onde é agir de acordo com o que está no buffer. Uma coisa a notar é que os retornos de chamada pode ir para baixo para o mecanismo de script, altura em que nada é certo o que pode acontecer.

Cada vez que uma chamada de retorno acabamentos, a corrente buffer de recepção deve ser confirmada etc. Callbacks atualmente não têm a capacidade de retornar um valor, porque, como disse antes, tudo pode acontecer.

O que acontece é que, quando em algum lugar no callback algo diz this-> disconnect (), eu quero desligar imediatamente o Client, removê-lo da EventManager e, finalmente, removê-lo da Server, onde também deve se finalmente destruído e memória livre. No entanto, ainda tenho algum código em execução após a conclusão de retorno de chamada no cliente, portanto, eu não posso memória livre.

O que devo mudar no design? Devo ter algum evento programado no Server que verificações que Clients estão livres para destruir? Oxalá criar sobrecarga adicional Eu não preciso? Será que ainda ser aprovado após a conclusão da chamada de retorno para executar código mínimo na pilha (return -1;) ou não?

Eu não tenho nenhuma idéia do que fazer, mas estou aberto para revamps projeto completo.

Agradecemos antecipadamente.

Foi útil?

Solução

Você pode usar um ponteiro de referência contados como boost::shared_ptr<> ao gerenciamento de memória simplificar. Se lista cliente usa shared_ptrs do gerente e do código que chama os retornos de chamada cria uma cópia local do shared_ptr o retorno de chamada é chamado, o objeto vai ficar vivo até que seja removido do gerenciador de e a função de retorno é 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
  }
}

O objeto Client será automaticamente eliminado uma vez que a última shared_ptr a ele sai do escopo, mas não antes. Então, criar uma cópia local do shared_ptr antes de uma chamada de função garante que o objeto não é excluído inesperadamente.

Outras dicas

Você deve considerar ter um objeto como "Session", que irá acompanhar determinado fluxo de mensagens do início ao fim (de 1 cliente). Este objeto também deve cuidar de estado atual: principalmente os buffers e processamento. Cada evento que desencadeia uma chamada de retorno deve atualizar o estado de sessão correspondente. Libevent é capaz de fornecê-lo com qualquer resultado de evento programado: sucesso, fracasso, timeout. Cada um destes tipos devem ser refletidos com sua lógica. Em geral, quando se trabalha com eventos, considere a sua lógica de processamento para ser um autômato com um estado.

http://en.wikipedia.org/wiki/Reactor_pattern pode ser uma boa de recursos para a sua tarefa.

Deixe a função de cliente :: disconnect () enviar um evento para o EventManager (ou servidor) classe. Isso significa que você precisa de algum tipo de manipulação de eventos em EventManager (ou Server), um ciclo de eventos, por exemplo.

A minha ideia geral é que cliente :: disconnect () não desconecta o cliente imediatamente, mas somente após o retorno terminado a execução. Em vez disso, ele apenas mensagens de um evento ao EventManager (ou servidor) classe.

Pode-se argumentar que o método Cliente :: disconnect () está na classe errada. Talvez ela deve ser Servidor :: desconexão (Cliente * c). Isso seria mais em linha com a ideia de que o servidor 'possui' o cliente e é o servidor que desconecta clientes (e atualiza alguns contabilidade interna).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top