现在的位置: 首页 > 综合 > 正文

World服务器的启动过程

2018年01月09日 ⁄ 综合 ⁄ 共 6340字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.