游戏服务器之逻辑服务基础说的是业务逻辑的服务模块的实现。
设计上:每个服务器对象有多个服务。每个服务有一个、多个线程来完成需要的逻辑,作为一个读者或者多个读者来实现。网络的线程部分是作为写者。读者写者的交互是使用python的Queue来作为逻辑消息队列,实现多线程的安全。
1、服务基础
(1)服务基类
(2)多线程服务(3)单线程服务
(4)没有单独线程的服务
2、服务应用
1、服务基础
(1)服务基类
封装服务消息队列和服务控制函数
class BaseService:
u"""
.该类为所有服务类的基类
.每个服务运行于一个独立的线程中,系统保证onEvent是线程安全的函数
"""
def __init__(self, server, serviceId, qSize=1024):
u"""
.构造函数,一般情况下用户服务不需要定义自己的构造函数,可通过定义的init()函数实现初始化功能
.如服务定义自己的构造函数,则需要调用本类的__init__函数
server为服务器对象实例
serviceId为自身的服务标识
qSize为消息队列的长度,超出该队列长度的消息,将被丢弃
"""
self.server = server
self.queue = Queue(qSize)
self.serviceId = serviceId
def getServiceId(self):
return self.serviceId
def dispatch(self, event):
u"""
.服务器在收到事件后,会调用该方法把事件放入队列中
.队列满时则不能存放新的消息,并抛出异常
.用户服务不能重定义该方法
"""
try:
#log.info(u"queue size:%s",self.queue.qsize())
self.queue.put(event)
except:
log.error(traceback.print_exc())
def dispatchTimerEvent(self, timerEvent):
u"""
. 服务器定时器到时后,会调用该方法把时间事件放入队列中
. 队列满时则等待,直到可以放入或超时为止
. 用户不能重定义该方法,如果定时器事件不能放入,则是严重的事件
. TODO: to be review
"""
self.queue.put(timerEvent)
def init(self):
u"""
.初始化函数,服务可以通过重新定义该方法来完成初始化工作
"""
pass
def onEvent(self, event):
u"""
.用户服务需要重新定义该方法,实现自己的逻辑
"""
pass
def call_stop(self):
self.stop()
def stop(self):
u"""
. 停止服务,用户服务需要重定义此方法
"""
log.info("%s unhand stop", self.__class__)
(2)多线程服务
启动多个线程,消息队列queue保证线程安全
class IMultiTaskService(BaseService):
def __init__(self, server, serviceId, qSize=1024, threadsNumber=5):
BaseService.__init__(self, server, serviceId, qSize)
self.init()
self.threads = []
for i in range(0, threadsNumber):
thread = Thread(target=self.run)
thread.setDaemon(True)
thread.start()
self.threads.append(thread)
log.info(u"service %d is started", serviceId)
def run(self):
while True:
try:
msg = self.queue.get(True)
if (msg.eventType == 0):
if msg.eventData == "QUIT":
self.call_stop()
break
self.onEvent(msg)
except:
log.error(traceback.print_exc())
(3)单线程服务
启动多个线程,消息队列queue保证线程安全
class IService(BaseService):
def __init__(self, server, serviceId, qSize=1024):
BaseService.__init__(self, server, serviceId, qSize)
self.init()
self.thread = Thread(target=self.run)
self.thread.setDaemon(True)
self.thread.start()
log.info(u"service %d is started", serviceId)
def run(self):
u"""
. 该方法从队列中获取事件并调用用户服务onEvent方法
. 用户服务不能重定义该方法
. TODO: to be review
"""
while True:
try:
msg = self.queue.get(True)
if (msg.eventType == 0):
if msg.eventData == "QUIT":
self.call_stop()
break
self.onEvent(msg)
except:
log.error(traceback.print_exc())
(4)没有单独线程的服务
class NoThreadService(BaseService):
u"""
. 该服务不单独开启线程,直接处理消息,所有事务处理在twisted主线程中,用于密集计算
"""
def __init__(self, server, serviceId, qSize=1024):
BaseService.__init__(self, server, serviceId, qSize)
self.init()
log.info(u"service %d is started", serviceId)
def dispatch(self, event):
try:
self.onEvent(event)
except:
log.error(traceback.print_exc())
2、服务应用
ai服务
单线程的ai服务,处理ai逻辑。
class BattleService(IService, SpelService):
u"""
. 战斗服务器
. 1 接收客户端消息
. 2 AI服务消息
. 3 计算伤害
. 4 发送到客户端与AI同步
"""
def init(self):
self.event_handlers = {
BATTLE_ROLE_ATTACK.REQ: self.handle_role_attack,
......
}
def handle_role_attack(self, event):
u"""
. 角色攻击事件
. 1 技能施放控制
"""
......
装备服务
class EquipmentService(IMultiTaskService):
......