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 设为一个普通类并在您的游戏中创建一个。

我支持使用 std::vector 而不是您自己的数组的建议。这将使您的代码更健壮,并使您更容易设置客户端,为每个客户端使用正确的构造函数,而不是为它们使用某种默认构造函数。

您不应该担心内存碎片 - 这是一个如此深奥的低级细节,您甚至不应该考虑它。它对你来说是个问题的可能性很小。但即使这是一个问题,我们也无法根据您在此处发布的内容进行诊断,因为我们不知道什么构成了 Client 类。如果 Client 类本身在其他地方引用各种内存,那么在 ClientManager 类中拥有一个精心管理的池是没有意义的。在这个阶段,您应该专注于编写健壮且正确的代码,并在以后需要时进行优化。

您也可以从 ClientManager::get 返回一个指针。只要确保在使用它之前检查它是否为空。如果您选择不同的接口,例如,您可以完全消除从 ClientManager 返回客户端的需要。将操作 do_something 与数据一起传递给 ClientManager 的成员,该成员将查找客户端并在找到客户端时调用该操作,否则报告错误。(虽然没有充分的理由找不到它,但如果您的 ClientManager 是正确的。)

于 2010-02-26T10:36:14.030 回答