Управляемый событиями клиент / серверный дизайн с C ++ - PullRequest
0 голосов
/ 21 сентября 2009

Я проектирую игровой сервер с возможностями сценариев. Общий дизайн выглядит так:

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.

Теперь последняя часть - самая сложная для меня сейчас.

В настоящее время мой дизайн позволяет мне для класса, который наследует Client, создавать обратные вызовы для определенных полученных событий. Этими обратными вызовами управляют в списке, и полученный буфер проходит процесс синтаксического анализа каждый раз, когда что-то получено. Если буфер действителен, обратный вызов вызывается, когда он воздействует на то, что находится в буфере. Следует отметить, что обратные вызовы могут передаваться в механизм сценариев, и в этот момент ничто не может быть уверенным в том, что может произойти.

Каждый раз, когда завершается обратный вызов, текущий буфер приема должен быть сброшен и т. Д. В настоящее время обратные вызовы не имеют возможности вернуть значение, потому что, как было сказано ранее, все может произойти.

Что происходит, когда где-то в обратном вызове что-то говорит это-> disconnect (), я хочу немедленно отключить Client, удалить его из EventManager и, наконец, удалить его из Server, где это также должно получить окончательно разрушенную и свободную память. Тем не менее, у меня все еще есть код, выполняющийся после завершения обратного вызова в клиенте, поэтому я не могу освободить память.

Что я должен изменить в дизайне? Должен ли я иметь какое-то временное событие в Server, которое проверяет, какие Client можно уничтожить? Это создаст дополнительные накладные расходы, которые мне не нужны? Будет ли нормально после завершения обратного вызова выполнить минимальный код в стеке (return -1;) или нет?

Понятия не имею, что делать, но я готов к полной модернизации дизайна.

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 21 сентября 2009

Вам следует рассмотреть возможность создания объекта типа «Сессия», который будет отслеживать определенный поток сообщений от начала до конца (от 1 клиента). Этот объект также должен заботиться о текущем состоянии: прежде всего, о буферах и обработке. Каждое событие, которое запускает обратный вызов, ДОЛЖНО обновлять состояние соответствующего сеанса. Libevent может предоставить вам любой результат запланированного события: успех, неудача, тайм-аут. Каждый из этих типов должен быть отражен вашей логикой. В общем, при работе с событиями считайте, что ваша логика обработки является автоматом с состоянием.

http://en.wikipedia.org/wiki/Reactor_pattern может быть хорошим ресурсом для вашей задачи.

1 голос
/ 21 сентября 2009

Вы можете использовать указатель с подсчетом ссылок, например boost::shared_ptr<>, чтобы упростить управление памятью. Если в списке клиентов менеджера используются shared_ptr s, а код, который вызывает обратные вызовы, создает локальную копию shared_ptr, для которого вызывается обратный вызов, объект будет оставаться активным до тех пор, пока он не будет удален из менеджера и * 1005. * функция обратного вызова завершена:

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

Объект Client будет автоматически удален после того, как последний shared_ptr выйдет за его пределы, но не раньше. Таким образом, создание локальной копии shared_ptr до вызова функции гарантирует, что объект не будет удален неожиданно.

0 голосов
/ 21 сентября 2009

Пусть функция Client :: disconnect () отправляет событие в класс EventManager (или Server). Это означает, что вам нужна какая-то обработка событий в EventManager (или Server), например, цикл обработки событий.

Моя общая идея заключается в том, что Client :: disconnect () не отключает клиента немедленно, а только после завершения обратного вызова. Вместо этого он просто отправляет событие в класс EventManager (или Server).

Можно утверждать, что метод Client :: disconnect () находится в неправильном классе. Может быть, это должен быть Server :: disconnect (Client * c). Это больше соответствовало бы идее, что Сервер «владеет» Клиентом, а именно Сервер отключает Клиентов (а затем обновляет некоторую внутреннюю бухгалтерию).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...