多线程游戏服务器是怎么写的?
如果有 4 个线程,是否有 1 个线程运行游戏循环,3 个接受和处理请求?另外:信息是从运行游戏循环的线程发送的吗?
多线程游戏服务器是怎么写的?
如果有 4 个线程,是否有 1 个线程运行游戏循环,3 个接受和处理请求?另外:信息是从运行游戏循环的线程发送的吗?
主要的关键是确保您的游戏逻辑不受线程模型的影响。
因此,大多数游戏服务器看起来像这样:
main() {
gGlobalReadOnlyStuff = LoadReadOnlyStuff();
SpawnThreads(numCores); // could be another limiting resource...
WaitForThreadsToBeReadyToGo();
while(1) {
WaitForNetworkInput(networkInput);
switch(networkInput.msg) {
case ADMIN_THING: // start/stop websever, dump logs, whatever...
DoAdminThing(networkInput.params);
break;
case SPAWN_GAME: // replace 'game' with 'zone' or 'instance' as needed
idThread = ChooseBestThread(); // round robin, random, etc
PostStartGameMessageToThread(idThread, networkInput.msg);
break;
// ...
}
}
}
void ThreadUpdate() {
threadLocalStuff = LoadThreadLocalStuff();
SignalThreadIsReadyToGo();
while(1) {
lock(myThreadsMessageQueue);
// copy messages to keep lock short
localMessageQueue = threadsMessageQueue;
unlock(myThreadsMessageQueue);
foreach(message in localMessageQueue) {
switch(message.msg) {
case SPAWN_GAME:
threadLocalStuff.games.MakeNewGame(message.params));
break;
case ADMIN_THING__LET_EVERYONE_KNOW_ABOUT_SERVER_RESET:
...;
break;
// etc...
}
}
foreach(game in threadLocalStuff.games) {
game.Update(); // game will handle its own network communication
}
}
两个困难的事情是“想出一个适合你的游戏的分区(游戏、区域、实例等)”和“在这些边界上转换东西(玩家、火球、史诗 lootz)”一个典型的答案是“通过序列化它一个数据库”,但你可以使用套接字/消息/文件/任何东西。但是,是的,在哪里以及如何制作这些分区以及最小化可能跨越边界的内容与您的游戏设计密切相关。
(是的,根据您的设置,可能有一些“共享”系统(日志记录、内存)可能需要多线程处理(或者甚至更好,每个线程只有一个记录器/堆))
Starkey 已经指出,这在很大程度上取决于精确的设计。
例如,在有许多客户端的游戏中,您会分配专用线程来处理输入,但对于有少数客户端(例如 <=16)的游戏,则不需要多个线程。
有些游戏的 NPC 具有相当的智慧。在他们自己的线程上运行它们可能很聪明,但如果你有太多,你将需要一个线程池,以便一堆 NPC 可以共享一个线程。
如果你有一个持久的世界,你需要将状态写到硬盘的某个地方(可能通过数据库)。由于这具有严重的延迟,因此您不希望在该 I/O 上等待主游戏循环。那将是另一个线程。
最后,还有一个问题是你是否有一个主游戏循环。MMO 会只有一个循环,还是您宁愿有很多?