0

スクリプト機能を備えたゲームサーバーを設計しています。一般的な設計は次のようになります。

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特定の受信イベントへのコールバックを作成するために継承するクラスを使用できます。これらのコールバックはリストで管理され、受信したバッファーは、何かを受信するたびに解析プロセスを実行します。バッファが有効な場合、コールバックが呼び出され、バッファ内の内容に基づいて動作します。注意すべき点の1つは、コールバックがスクリプトエンジンに到達する可能性があることです。この時点では、何が発生するかはわかりません。

コールバックが終了するたびに、現在の受信バッファをリセットする必要があります。前述のように、何かが発生する可能性があるため、コールバックには現在、値を返す機能がありません。

何が起こるかというと、コールバックのどこかでthis-> disconnect()と表示されたら、すぐに切断してClient、から削除しEventManager、最後に、から削除しServerます。ここで、最終的に破棄され、メモリが解放されます。ただし、クライアントでコールバックが終了した後もコードが実行されているため、メモリを解放できません。

デザインで何を変更すればよいですか?どのが自由に破壊できるかServerをチェックする時限イベントが必要ですか?Clientそれは私が必要としない追加のオーバーヘッドを作成しますか?コールバックが終了した後でも、スタック(return -1;)で最小限のコードを実行しても問題ありませんか?

どうすればいいのかわかりませんが、デザインを完全に刷新する準備ができています。

前もって感謝します。

4

3 に答える 3

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、関数呼び出しの前にローカルコピーを作成すると、オブジェクトが予期せず削除されないようになります。

于 2009-09-21T14:05:47.840 に答える
1

(1つのクライアントからの)特定のメッセージフローを最初から最後まで追跡する「Session」のようなオブジェクトを用意することを検討する必要があります。このオブジェクトは、現在の状態(主にバッファーと処理)も処理する必要があります。コールバックをトリガーする各イベントは、対応するセッションの状態を更新する必要があります。Libeventは、スケジュールされたイベントの結果(成功、失敗、タイムアウト)を提供することができます。この各タイプは、ロジックに反映されている必要があります。一般に、イベントを操作するときは、処理ロジックを状態のあるオートマトンと見なしてください。

http://en.wikipedia.org/wiki/Reactor_patternは、タスクに適したリソースである可能性があります。

于 2009-09-21T14:52:56.137 に答える
0

Client ::disconnect()関数がEventManager(またはサーバー)クラスにイベントを送信するようにします。これは、EventManager(またはサーバー)で何らかのイベント処理が必要であることを意味します。たとえば、イベントループです。

私の一般的な考え方は、Client :: disconnect()はクライアントをすぐに切断するのではなく、コールバックの実行が終了した後にのみ切断するというものです。代わりに、イベントをEventManager(またはサーバー)クラスに投稿するだけです。

Client :: disconnect()メソッドが間違ったクラスにあると主張する人もいるかもしれません。多分それはServer::disconnect(Client * c)であるはずです。これは、サーバーがクライアントを「所有」し、クライアントを切断する(そして内部の簿記を更新する)サーバーであるという考えとより一致します。

于 2009-09-21T14:30:12.527 に答える