2

私は C++ プログラミングが初めてで、オブジェクト マネージャーをマルチプレイヤー ゲームにコーディングしていますが、クライアント オブジェクトの管理方法について疑問があります。クライアント オブジェクトは、接続されたクライアント パラメータ (IP、接続時間、受信データなど) で構成されます。

メモリの断片化を避けるために、許可されているクライアントの最大数でオブジェクト プールを割り当てることを計画しています。そのために、次のようなクライアント オブジェクト マネージャーをコーディングしています。

ClientManager.h

#include "Client.h"

class ClientManager { 
public: 
static void init(int max); //initialize pool (allocate memory) 
static void dispose(); //dispose pool (deallocate memory) 
static bool add(int socketFd); //add connected client by its socket file descriptor 
static bool remove(int socketFd); //remove connected client by its socket fd
static Client& get(int socketFd); //get the client object by its socket fd

private: 
Client* clientList; //array of allocated clients objects
int maxClient; //max number of connected clients allowed

このクラスは静的な方法でのみ呼び出されるため、コンストラクタ/デストラクタはありません。異なるタイプのオブジェクト間でクライアント データを読み取り/変更できることが必須であるため、このクラスは静的である必要があります。

実装は次のようになります。

ClientManager.cpp

void ClientManager::init(int max) {
maxClient = max;
clientList = new Client[maxClient];
}

void ClientManager::dispose() {
maxClient = 0;
delete [] clientList;
clientList = NULL;
}

bool ClientManager::add(int socketFd) {
//search pool for non-initialized object
//if(there is a non-initializes object) { initialize it with socketFd and return true}
//else return false;
}

bool ClientManager::remove(int socketFd) {
//search pool for socketFd
//if(socketFd found) { clear object (make it non-initialized) and return true}
//else return false
}

Client& ClientManager::get(int socketFd) {
//search for object position
if(pos) return clientList[pos];
else ???????
}

では、get 関数でオブジェクトの戻り値を管理するにはどうすればよいでしょうか。それは参照による最良の選択肢ですか?ポインターを返したくありませんが、それが最後のオプションである場合は、それを受け入れることができます。プール内の登録済み (初期化済み) オブジェクトのみを確実に取得できると思いますが、get 関数でこのチェックが必要な場合はどうすればよいですか? コードを堅牢にし、実行時に停止しないようにしたいので、アサートは必要ありません (私は C++ を初めて使用するので、間違っていることを言っている場合は修正してください)。

メインプログラムでは、次のようなことを考えています:

Daemon.cpp

#include "ClientManager.h"

int main(...) {
ClientManager::init(100);

while(1) {
//do server stuff
//get onConnect event (new client is connecting)
//get onDisconnect event (connected client has gone offline)
//get onDataReceived event (connected client has sent data)
}
}

void onConnect(int socketFd) {
ClientManager::add(socketFd);
}

void onDisconnect(int socketFd) {
ClientManager::remove(socketFd);
}

void onDataReceived(int socketFd) {
do_something(ClientManager::get(socketFd).data);
}

私はそれを正しくやっていますか?ありがとう

注:
1) このコードは頭の中にあり、ここに入力したので、何か忘れている可能性があります。
2)プログラムは殺されることによってのみ終了するため(私はLinuxを使用しています)、メインプログラムでClientManager disposeメソッドが明示的に呼び出されることはありません(静的クラスであるため)。繰り返しますが、私が何か間違ったことを言っている場合は教えてください!
3) 私の悪い英語について申し訳ありません:)

4

2 に答える 2

3

いくつかのコメント:

  • std::vector を使用して、ある種の独自の構造ではなく、クライアント オブジェクトを保持します。それはあなたの人生を楽にするでしょう
  • get() が参照を返しても問題ないと思いますが、ユーザーが参照を長時間保持しすぎると無効になる可能性があることをユーザーが知っている場合
  • get()要素が存在しない場合は、例外をスローします。それが例外の目的であり、不足している要素を適切なレベルで処理できるようになります

(2) に関しては、適切なシグナルを処理して dispose() を呼び出すことができます。終了する前に、おそらくソケットを閉じたいと思うでしょう。

于 2010-02-25T21:25:36.990 に答える
1

多くのメンバーを静的にしても、「静的クラス」にはなりません。これは、静的メンバー関数を持つ、他のクラスと同じです。いずれにせよ、これを行う必要はありません。ClientManager を通常のクラスにして、それらの 1 つをゲーム内に作成するだけです。

独自の配列の代わりに std::vector を使用するようにアドバイスします。これにより、コードがより堅牢になり、多くのクライアントに対して何らかのデフォルトのコンストラクターを使用する代わりに、クライアントごとに適切なコンストラクターを使用して、クライアントのセットアップが容易になります。

メモリの断片化について心配する必要はありません。これは非常に難解な低レベルの詳細であるため、考えるべきではありません。それがあなたにとって問題になる可能性は天文学的に小さいです。しかし、それが問題であったとしても、ここに投稿された内容に基づいて診断することはできませんでした。なぜなら、クライアント クラスを構成する要素がわからないからです。Client クラス自体があらゆる種類のメモリを他の場所で参照している場合、ClientManager クラスに慎重に管理されたプールを用意しても意味がありません。この段階では、堅牢で正しいコードを書くことに集中し、必要に応じて後で最適化する必要があります。

ClientManager::get からポインタを返すこともできます。使用する前に null かどうかを確認してください。別のインターフェイスを選択すると、ClientManager からクライアントを返す必要が完全になくなります。操作 do_something をデータとともに ClientManager のメンバーに渡します。ClientManager はクライアントを検索し、クライアントが見つかった場合は操作を呼び出し、見つからなかった場合はエラーを報告します。(ただし、ClientManager が正しければ、見つからないという正当な理由はありません。)

于 2010-02-26T10:36:14.030 に答える