質問

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

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を継承するクラスのために私を可能にします。これらのコールバックは、リスト内で管理され、受信バッファは、各時間何かが受信され、解析プロセスを経ます。バッファが有効であれば、それはバッファ内にあるものに作用ここで、コールバックが呼ばれています。もう一つ注意すべきは、コールバックはポイントは何も何が起こるかわからないですこれで、スクリプトエンジン、にまで行くことができるということです。

以前のように述べられているので、

たびにコールバックが終了すると、現在の受信バッファは、などのコールバックをリセットする必要があり、現在、何かが起こることができ、値を返すのない機能を持っていません。

何が起こるかというと、コールバック何かでどこかがthis->切断()と言うとき、私はすぐにClientを切断する、EventManagerからそれを削除し、そして最後に、それはまた、最終的に破壊されるはずですServer、からそれを削除することですそして空きメモリ。しかし、私はまだいくつかのコードは、このように私は空きメモリことはできませんが、クライアントでのコールバックが終了した後に実行しています。

私はデザインに何を変更する必要がありますか?私は破壊して自由であるServersチェック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のローカルコピーを作成します。

他のヒント

あなたは(1つのクライアントから)最初から最後まで、特定のメッセージ・フローを追跡する「セッション」のようなオブジェクトを検討する必要があります。 主バッファおよび処理:このオブジェクトは、現在の状態の世話をする必要があります。 コールバックをトリガする各イベントは、セッション対応の状態を更新する必要があります。 成功、失敗、タイムアウト:Libeventは、スケジュールされたイベントのいずれかの結果をご提供することが可能です。このタイプのそれぞれは、あなたのロジックに反映されなければなりません。 イベントで作業する場合、一般的には、状態とオートマトンであるためにあなたの処理ロジックを考えています。

http://en.wikipedia.org/wiki/Reactor_pattern には良いかもしれあなたのタスクのためのリソースます。

クライアント::切断()関数はEventManager(またはサーバ)クラスにイベントを送信してみましょう。これは、あなたがEventManager(またはサーバ)、インスタンスのイベントループでのイベント処理のいくつかの並べ替えが必要であることを意味します。

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top