您的位置:首页 > 其它

World服务器的启动过程

2011-07-28 20:59 239 查看
1、Mian函数的最后会调用Master.Run函数,Master.Run的最后工作是启动World的网络侦听,通过调用WorldSocketMgr.StartNetwork实现。

///- 运行World侦听Socket
//从配置文件获取World侦听端口
uint16 wsport = sWorld.getConfig (CONFIG_UINT32_PORT_WORLD);
//从配置文件获取World服务器绑定IP;如果没有设定,则绑定本机网卡任意IP
std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0");
if (sWorldSocketMgr->StartNetwork (wsport, bind_ip) == -1)
{
sLog.outError ("Failed to start network");
Log::WaitBeforeContinueIfNeed();
World::StopNow(ERROR_EXIT_CODE);
// go down and shutdown the server
}
//线程阻塞
sWorldSocketMgr->Wait ();

2、WorldSocketMgr主要工作启动World的端口侦听服务,WorkldSocket的管理,Ractor线程的管理
WorldSocketMgr.StartNetwork没有作什么工作,只是简单地调用了StartReactiveIO。
int WorldSocketMgr::StartNetwork (ACE_UINT16 port, std::string& address)
{
m_addr = address;
m_port = port;
if (!sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG))
ACE_Log_Msg::instance ()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS);
if (StartReactiveIO (port, address.c_str()) == -1)
return -1;
return 0;
}

SartReactiveIO的工作负责初始化反应器线程,每个反应器线程中由一个反应器来响应分配到这个线程的WorldSocket的消息,Mangos初始配置是2个反应器线程。然后实例化WorldSocket.Acceptor,开始侦听World服务端口,最后启动所有反应器线程。
int WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address)
{
m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true);
//最大反应器线程数
int num_threads = sConfig.GetIntDefault ("Network.Threads", 1);
if (num_threads <= 0)
{
sLog.outError ("Network.Threads is wrong in your config file");
return -1;
}
//不知道为什么要加1?
m_NetThreadsCount = static_cast<size_t> (num_threads + 1);
//初始化线程
m_NetThreads = new ReactorRunnable[m_NetThreadsCount];
BASIC_LOG("Max allowed socket connections %d",ACE::max_handles ());
// -1 means use default
m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1);
//?难道是指字符为Unicode类型缓冲区
m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536);
if ( m_SockOutUBuff <= 0 )
{
sLog.outError ("Network.OutUBuff is wrong in your config file");
return -1;
}
//Acceptor对象
WorldSocket::Acceptor *acc = new WorldSocket::Acceptor;
m_Acceptor = acc;
//开始侦听
ACE_INET_Addr listen_addr (port, address);
if (acc->open (listen_addr, m_NetThreads[0].GetReactor (), ACE_NONBLOCK) == -1)
{
sLog.outError ("Failed to open acceptor ,check if the port is free");
return -1;
}
//启动所有反应器线程
for (size_t i = 0; i < m_NetThreadsCount; ++i)
m_NetThreads[i].Start ();
return 0;
}
3、当有客户端连接到World服务时,会调用WorldSorket.open,WorldSocket继承ACE_svc_Handler。Open会调用一个钩子WorldSocketMgr.OnSocketOpen(该函数的功能主要负责将WorldSocket分配到相应的反应器线程,由该反应器处理它的消息循环)。然后发送一个回应包给客户端。最后向反应器注册它要处理的事件。

//由接受器工厂在连接建立之后调用的时候调用
int WorldSocket::open (void *a)
{
ACE_UNUSED_ARG (a);
// 假设可能两次调用这个函数
if (m_OutBuffer)
return -1;
// 假设当我们初始化它时,被更新
m_OutActive = true;
// 钩子函数(触发WorldSocketManager::OnSocketOpen)
if (sWorldSocketMgr->OnSocketOpen (this) == -1)
return -1;
// 分配缓冲区内存
ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1);
//远端网络地址
ACE_INET_Addr remote_addr;
if (peer().get_remote_addr (remote_addr) == -1)
{
sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno));
return -1;
}
//远端主机名
m_Address = remote_addr.get_host_addr ();
// 发送启动(开始)包.
WorldPacket packet (SMSG_AUTH_CHALLENGE, 24);
packet << uint32(1); // 1...31
packet << m_Seed;
//随机加密码种子(16位)
BigNumber seed1;
seed1.SetRand(16 * 8);
packet.append(seed1.AsByteArray(16), 16); // new encryption seeds
//随机加密码种子(16位)
BigNumber seed2;
seed2.SetRand(16 * 8);
packet.append(seed2.AsByteArray(16), 16); // new encryption seeds
if (SendPacket (packet) == -1)
return -1;
// 反应器注册事件
if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1)
{
sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno));
return -1;
}
// reactor takes care of the socket from now on
remove_reference ();
return 0;
}

4、WorldSocketMgr.OnOSocketpen函数在WorldSocket.Open(当客户连接时)中被调用。
首先是设置WorldSocket使用的数据缓冲区,设置Tcp有需要发送的数据时立即发送。将WorldSocket分配到相应的反应器线程(负载均衡)。

//当客户连接时触发
int WorldSocketMgr::OnSocketOpen (WorldSocket* sock)
{
// set some options here
if (m_SockOutKBuff >= 0)
{
if (sock->peer ().set_option (SOL_SOCKET,
SO_SNDBUF,
(void*) & m_SockOutKBuff,
sizeof (int)) == -1 && errno != ENOTSUP)
{
sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF");
return -1;
}
}
static const int ndoption = 1;
// 设置TCP_NODELAY,关闭Nagle算法,使数据立即发送
if (m_UseNoDelay)
{
if (sock->peer ().set_option (ACE_IPPROTO_TCP,
TCP_NODELAY,
(void*)&ndoption,
sizeof (int)) == -1)
{
sLog.outError ("WorldSocketMgr::OnSocketOpen: peer ().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno));
return -1;
}
}
//设置Socket缓冲区大小 
sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff);
// we skip the Acceptor Thread
size_t min = 1;
ACE_ASSERT (m_NetThreadsCount >= 1);
//寻找处理Socket数最少的线程
for (size_t i = 1; i < m_NetThreadsCount; ++i)
if (m_NetThreads[i].Connections () < m_NetThreads[min].Connections ())
min = i;
//将Socket加入到线程中
return m_NetThreads[min].AddSocket (sock);
}

5、RactorRunable负责启动反应器的消息循环。
virtual int svc ()
{
DEBUG_LOG ("Network Thread Starting");
//数据库线程开始工作
WorldDatabase.ThreadStart ();
ACE_ASSERT (m_Reactor);
SocketSet::iterator i, t;
while (!m_Reactor->reactor_event_loop_done ())
{
// dont be too smart to move this outside the loop
// the run_reactor_event_loop will modify interval
ACE_Time_Value interval (0, 10000);

if (m_Reactor->run_reactor_event_loop (interval) == -1)
break;
//将新的连接加入到Socket集合
AddNewSockets ();
//栓查每一个Socket是否正常,如果不正常则关闭
for (i = m_Sockets.begin (); i != m_Sockets.end ();)
{
if ((*i)->Update () == -1)
{
t = i;
++i;
(*t)->CloseSocket ();
(*t)->RemoveReference ();
--m_Connections;
m_Sockets.erase (t);
}
else
++i;
}
}

//任务结束前,结束数据线程
WorldDatabase.ThreadEnd ();
DEBUG_LOG ("Network Thread Exitting");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐