我对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)对不起,我的英语不好:)
发布于 2010-02-26 05:25:37
下面是几条评论:
get()
中抛出一个异常;这就是异常的用处,它将允许你在适当的级别上处理缺失的元素至于(2),您可以处理适当的信号并调用dispose()。我想您可能想在退出之前关闭插座。
发布于 2010-02-26 18:36:14
将大量成员设置为静态并不会使其成为“静态类”。它只是一个类,和其他类一样,都有静态成员函数。无论如何,您都不需要这样做:只需使ClientManager成为一个普通的类,并在游戏中创建其中的一个。
我再次建议使用std::vector而不是您自己的数组。这将使您的代码更健壮,并使您更容易设置客户端,为每个客户端使用适当的构造函数,而不是为许多客户端使用某种类型的默认构造函数。
你不应该担心内存碎片-这是一个如此深奥的底层细节,你甚至不应该考虑它。对你来说,这是一个极小的问题。但是即使它是一个问题,我们也不能根据您在这里发布的内容来诊断它,因为我们不知道Client类的组成。如果客户端类本身在其他地方引用了所有类型的内存,那么在ClientManager类中使用一个精心管理的池就没有意义了。在这个阶段,您应该专注于编写健壮和正确的代码,并在以后需要时进行优化。
您也可以从ClientManager::get返回一个指针。只需确保在使用它之前检查它是否为null。如果您选择不同的接口,则可以完全消除从ClientManager返回客户端的需要。将操作do_something与数据一起传递到ClientManager的一个成员中,该成员将查找客户端并在找到客户端时调用该操作,如果未找到则报告错误。(尽管如果您的ClientManager是正确的,那么没有理由找不到它。)
https://stackoverflow.com/questions/2337650
复制相似问题