Событийный дизайн клиента / Сервера с использованием C ++

StackOverflow https://stackoverflow.com/questions/1454455

  •  12-09-2019
  •  | 
  •  

Вопрос

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

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;) или нет?

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

Заранее благодарю.

Это было полезно?

Решение

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

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 перед вызовом функции убедитесь, что объект не был удален неожиданно.

Другие советы

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top