在上一篇博文中,我们分析了Mangos服务器的登陆服务器,Mangos登陆服务器主要就是验证用户的合法性,并且针对通过验证的用户发送游戏列表服务器列表,用户选择了相关游戏服务器时所涉及到的流程就是今天本博文需要分析的,Mangos游戏服务器的主要架构就是一对多的关系,下层的I/O是多线程的,而上层的游戏主逻辑是单线程的,两者的胶合部分就是已经封装好的session模块,好了,下面就来看看具体的流程细节吧,首先来看看游戏服务器(世界服务器)的主流程吧,代码如下:
extern int main(int argc,char** argv)
{
const char* cfg_file = _MANGOSD_CONFIG;
const char* options = ":a:c:s";
ACE_Get_Opt cmd_opts(argc,argv,options);
cmd_opts.long_option("version",'v',ACE_Get_Opt::NO_ARG);
cmd_opts.long_option("ahbot",'a',ACE_Get_Opt::ARG_REQUIRED);
char serviceDaemonMode = '\0';
int option;
while((option = cmd_opts())!= EOF)
{
switch (option)
{
case 'a':
break;
case 'c':
cfg_file = cmd_opts.opt_arg();
break;
case 'v':
return 0;
case 's':
break;
default:
break;
}
}
if(!sConfig.SetSource(cfg_file))
{
printf("Could not find configuration file %s\n",cfg_file);
return 1;
}
return sMaster.Run();
}
上述代码可能跟Mangos代码有部分出入,主要是为了看清整个流程而进行了精简,在上述代码中主要就是那个sMaster.run了,其他的就是一些配置方面的加载功能,好了,我们就顺着sMaster往下看看,代码如下:
int Master::Run()
{
std::string pidfile = sConfig.GetStringDefault("PidFile","");
if(!pidfile.empty())
{
uint32 pid = CreatePIDFile(pidfile);
if(!pid)
{
printf("Cannot create pid file %s\n",pidfile.c_str());
return 1;
}
}
if(!_StartDB())
{
return 1;
}
//sWorld.SetInitialWorldSettings();
CharacterDatabase.AllowAsyncTransactions();
WorldDatabase.AllowAsyncTransactions();
LoginDatabase.AllowAsyncTransactions();
_HookSignals();
ACE_Based::Thread world_thread(new WorldRunnable());
world_thread.setPriority(ACE_Based::Highest);
ACE_Based::Thread* cliThread = NULL;
#ifdef WIN32
if(sConfig.GetBoolDefault("Console.Enable",true) && (m_ServiceStatus == -1))
#else
if(sConfig.GetBoolDefault("Console.Enable",true))
#endif
{
cliThread = new ACE_Based::Thread(new CliRunnable());
}
ACE_Based::Thread* rar_thread = NULL;
if(sConfig.GetBoolDefault("Ra.Enable",false))
{
rar_thread = new ACE_Based::Thread(new RARunnable());
}
//uint16 port = sWorld.getConfig(CONFIG_UINT32_PORT_WORLD);
uint16 port = 17777;
std::string ip = sConfig.GetStringDefault("BindIP","0.0.0.0");
if(sWorldSocketMgr->StartNetwork(port,ip) == -1)
{
printf("Failed to start network\n");
World::StopNow(ERROR_EXIT_CODE);
}
sWorldSocketMgr->Wait();
_UnHookSignals();
world_thread.wait();
if(rar_thread)
{
rar_thread->wait();
rar_thread->destroy();
delete rar_thread;
}
//clearOnlineAccounts();
//sMassMailMgr.Update(true);
CharacterDatabase.HaltDelayThread();
WorldDatabase.HaltDelayThread();
LoginDatabase.HaltDelayThread();
#ifdef WIN32
cliThread->wait();
#else
cliThread->destroy();
#endif
delete cliThread;
return World::GetExitCode();
}
在上面的代码中,我们主要关注三点东西:1.数据库的初始化操作,2.世界主线程(游戏主线程)的初始化以及启动,3.底层的I/O线程的初始化以及启动,好了,我们就按照这三点来稍微看看,首先看第一点(1.数据库的初始化操作),代码如下:
bool Master::_StartDB()
{
std::string dbstring = sConfig.GetStringDefault("WorldDatabaseInfo","");
int nConnections = sConfig.GetIntDefault("WorldDatabaseConnections",1);
if(dbstring.empty())
{
printf("Database not specified in configuration file\n");
return false;
}
printf("World Database total connection:%d\n",nConnections+1);
if(!WorldDatabase.Initialize(dbstring.c_str(),nConnections))
{
printf("Cannot connect to world database %s\