转自:http://eric-weitm.iteye.com/blog/1457395
整个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由几个线程维护)