智慧 + 毅力 = 无所不能

正确性、健壮性、可靠性、效率、易用性、可读性、可复用性、兼容性、可移植性...

导航

mangos源码分析

Posted on 2012-08-11 13:42  Bill Yuan  阅读(10245)  评论(0编辑  收藏  举报

转自:http://eric-weitm.iteye.com/blog/1457395

mangos 的执行模型
一、线程分布:
1、主线程 main---- Master::Run() ,主要功能:初始化world、创建子线程、回收资源
2、WorldRunnable -------GS主线程
3、CliRunnable -----后台调试线程
4、RARunnable -------事件处理和分发线程
5、MaNGOSsoapRunnable---协议
6、FreezeDetectorRunnable
7、线程池  Master::Run----WorldSocketMgr::StartNetwork---WorldSocketMgr::StartReactiveIO ---ReactorRunnable

二、事件分发和处理
WorldRunnable::run---World:update----World:UpdateSessions---WorldSession::Update(一个socket内所有事件)---各种各样的handler

基本框架:ACE的Reactor机制(ACE_TP_Reactor)

三、WorldRunnable 主要功能
WorldRunnable ----World 定时器任务+网络事件(session中的)+异步IO回调+任务系统调度+cli

整个game server的并发模型

一 概述
game server至少要提供如下几类的功能 :
  1、响应客户端请求-------WorldRunnable
  2、后台命令  -------CliRunnable
  3、分布式架构(RMI等) -------MaNGOSsoapRunnable

可以看到针对这几类功能,mangos都给予了支持。

二、WorldRunnable响应客户端请求的并发实现
  game server会提供很多服务,如组队、加好友、交易、走路、战斗……,从宏观上讲这些服务是同时对外提供的,另外IO操作是费时的,
必须将IO与逻辑处理分开,这样的话一个基本的实现是这样的:
1、开启IO线程,所有费时的操作交由此处处理   WorldDatabase.ThreadStart();
2、利用协程来实现各个子系统,或者利用心跳来实现各个子系统的调度(不能开很多线程,线程代价太高)

三、Mangos的心跳实现
void World::Update(uint32 diff)
  基本上包括几类:
  1、检查定时器---------------时间
  2、刷任务
  3、维护session---------------------人物
  4、全局环境更新(map、battleGround)--------地点
  5、处理服务器事件------------------事件
  6、其他(数据同步、后台调试、IO回调……)

四、game server运行的机制
  1、定时器触发
  2、事件触发(松耦合)

五、典型的一种service的实现方式
1、IO协程将cammand入队
2、worker协程 依次fetch、execute
   核心数据结构是线程安全的队列

 

GS生命期内主要的事件---------状态机的状态转换主要是基于事件

一 game server状态机
startup
LOAD
Compile
init
running
shutdown

二 角色状态机
login
enter_world
enter_map
leave_map
leave_world
relogin
logout

三 角色commands的命令种类
login、auction, buy, chat, express, move, task, select_menu_item, stall……

四 server端service的组织
  1、结构化(纯c实现) clone, feature、cmds(命令入口filter)、daemons(抽象的功能模块)
  2、OO  各个层次的router,XXHandler, 一般在session中的总入口是player

 

session管理


一、world核心数据结构:环境+session
SessionMap m_sessions;
Queue m_QueuedSessions;
typedef UNORDERED_MAP<uint32, Weather*> WeatherMap;
        WeatherMap m_weathers;

二、WorldSession 核心数据结构 玩家+信道+消息队列
  Player *_player;
  WorldSocket *m_Socket;
  ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; // 每个session有一个消息队列

整个session就是不停的fetch,处理msg的过程
  OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];  // 利用一次映射找到handler
handle_input_payload----int WorldSocket::ProcessIncoming (WorldPacket* new_pct)--------void WorldSession::QueuePacket(WorldPacket* new_packet)

三、player核心数据结构 map、权限、社会关系、管理员?拍卖?谈话 存储 包裹 物品……

概述:所有command缓存在socket的队列中,各个子系统的总入口是player

服务端每一帧的逻辑:
1、从OS处取出到达的事件到本进程(所有的事件已经缓存在socket队列中)
2、依次调度各个子系统或子子系统

对于node.js而言,线程调度、事件缓存、回调机制已经都实现了,程序员只要实现具体的逻辑和定时器(子系统)就可以了

 

game server内嵌的http服务

如何使gs响应http的请求? 基本思路 实现简单的http server框架、具体游戏逻辑转发给内部handler来处理

一 初始化
  开启监听线程(协程)检查端口、设置缓冲区大小
  每一个socket连过来时 1、开新协程处理(有调度开销)  2、放入共享队列中,由worker线程池共同维护(有数据同步的问题)
  设置每个请求URI对应的回调接口

二 服务期
  1、一个socket数据到来后,开新线程,解析http数据,分析出请求的uri、回调、关闭socket、关闭线程(因为http是无连接的)
  2、一个socket到来时,其被放入某个thread内部的sockets数组中,
    当此worker thread池被调度到之后,依次处理每个socket的数据就可以了(唯一区别是多个sockets由几个线程维护)