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;
}