游戏开发论坛

 找回密码
 立即注册
搜索
楼主: qinglan

游戏服务器技术交流

[复制链接]

7

主题

82

帖子

110

积分

注册会员

Rank: 2

积分
110
QQ
 楼主| 发表于 2007-9-27 23:49:00 | 显示全部楼层

服务器公共组件 -- 事件与信号

  关于这一节,这几天已经打了好几遍草稿,总觉得说不清楚,也不好组织这些内容,但是打铁要趁热,为避免热情消退,先整理一点东西放这,好继续下面的主题,以后如果有机会再回来完善吧。本节内容欠考虑,希望大家多给点意见。

  有些类似于QT中的event与signal,我将一些动作请求消息定义为事件,而将状态改变消息定义为信号。比如在QT应用程序中,用户的一次鼠标点击会产生一个鼠标点击事件加入到事件队列中,当处理此事件时可能会导致某个按钮控件产生一个clicked()信号。

  对应到我们的服务器上的一个例子,玩家登录时会发给服务器一个请求登录的数据包,服务器可将其当作一个用户登录事件,该事件处理完后可能会产生一个用户已登录信号。

  这样,与QT类似,对于事件我们可以重定义其处理方法,甚至过滤掉某些事件使其不被处理,但对于信号我们只是收到了一个通知,有些类似于Observe模式中的观察者,当收到更新通知时,我们只能更新自己的状态,对刚刚发生的事件我不已不能做任何影响。

  仔细来看,事件与信号其实并无多大差别,从我们对其需求上来说,都只要能注册事件或信号响应函数,在事件或信号产生时能够被通知到即可。但有一项区别在于,事件处理函数的返回值是有意义的,我们要根据这个返回值来确定是否还要继续事件的处理,比如在QT中,事件处理函数如果返回true,则这个事件处理已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处理函数的返回值对信号分派器来说是无意义的。

  简单点说,就是我们可以为事件定义过滤器,使得事件可以被过滤。这一功能需求在游戏服务器上是到处存在的。

  关于事件和信号机制的实现,网络上的开源训也比较多,比如FastDelegate,sigslot,boost::signal等,其中sigslot还被Google采用,在libjingle的代码中我们可以看到他是如何被使用的。

  在实现事件和信号机制时或许可以考虑用同一套实现,在前面我们就分析过,两者唯一的区别仅在于返回值的处理上。

  另外还有一个需要我们关注的问题是事件和信号处理时的优先级问题。在QT中,事件因为都是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上派发,直到有一个窗口返回true,截断了事件的处理为止。对于信号的处理则比较简单,默认是没有顺序的,如果需要明确的顺序,可以在信号注册时显示地指明槽的位置。

  在我们的需求中,因为没有窗口的概念,事件的处理也与信号类似,对注册过的处理器要按某个顺序依次回调,所以优先级的设置功能是需要的。

  最后需要我们考虑的是事件和信号的处理方式。在QT中,事件使用了一个事件队列来维护,如果事件的处理中又产生了新的事件,那么新的事件会加入到队列尾,直到当前事件处理完毕后,QApplication再去队列头取下一个事件来处理。而信号的处理方式有些不同,信号处理是立即回调的,也就是一个信号产生后,他上面所注册的所有槽都会立即被回调。这样就会产生一个递归调用的问题,比如某个信号处理器中又产生了一个信号,会使得信号的处理像一棵树一样的展开。我们需要注意的一个很重要的问题是会不会引起循环调用。

  关于事件机制的考虑其实还很多,但都是一些不成熟的想法。在上面的文字中就同时出现了消息、事件和信号三个相近的概念,而在实际处理中,经常发现三者不知道如何界定的情况,实际的情况比我在这里描述的要混乱的多。

  这里也就当是挖下一个坑,希望能够有所交流。

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2007-9-28 10:24:00 | 显示全部楼层

Re:游戏服务器技术交流

我一般是使用Command模式的:
一、如果是与网络另一端的节点交流,那么就发送一个Command对象给对方;
二、如果是本地交流:
(1).如果是同步的,那么就只是调用目标对象的函数;
(2.)如果是异步的,那么就会生成一个Command对象,并且把它加入到队列里,然后在游戏循环中会有专门的一步来处理这个队列里所有的Command对象。

管理Command对象的那个队列,我把它封装为MessageRouter,从网络连接那里读取到的Command对象也会push进入MessageRouter。
伪码:

  1. class Command
  2. {
  3. public:
  4.     ……
  5.     virtual ~Command();
  6.     virtual bool process(void);//这里process函数的参数也可以是某个对象的引用,通过它能够得到大多数所需要的数据
  7.     virtual bool load();
  8.     virtual bool save();//这里的load和save是对象序列化函数,用于从网络上收取Command或者发送Command
  9. };

  10. class MessageRouter
  11. {
  12. public:
  13.     void push( Command* );
  14.     void process()
  15.     {
  16.         for( each cmd ){
  17.             if( cmd->process() ){
  18.                 erase( cmd );
  19.             }
  20.         }
  21.     }
  22. protected:
  23.     std::list<Command*> _cmds;
  24. };
复制代码

另外也可以在MessageRouter里加入时间或其他的状态来触发或抑制Command的process的调用。

59

主题

1490

帖子

1496

积分

金牌会员

Rank: 6Rank: 6

积分
1496
发表于 2007-9-28 12:11:00 | 显示全部楼层

Re:游戏服务器技术交流

都走偏了。。。我不该说的,只看看。你们请继续,呵呵

89

主题

822

帖子

847

积分

高级会员

Rank: 4

积分
847
发表于 2007-9-28 12:15:00 | 显示全部楼层

Re:游戏服务器技术交流

事件机制我一般只针对客户端,服务器端重来不搞这些东西,服务器端我个人习惯全部使用switch-case,交给脚本或者其他模块去处理,只有少数系统消息被过滤,其他一概不管,而且客户端的事件机制全部都要放到队列中排队,尽管COM支持多线程,但DX经常出现Crash,那种研究客户端多线程的人,我只能表示佩服,自己是没有那个精力搞。

我也不习惯把一个事件交给多个对象处理,类似Windows消息机制,子窗口响应,子窗口的子窗口还响应,这个在游戏中也很危险,除了在底层的少数消息我自己处理,其他的逻辑上我仅仅处理一次,如果需要多个对象同时处理一个消息,由逻辑自己传递消息处理指针,我不在网络模块实现他。

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2007-9-28 15:53:00 | 显示全部楼层

Re: Re:游戏服务器技术交流

6377: Re:游戏服务器技术交流

都走偏了。。。我不该说的,只看看。你们请继续,呵呵

拜一个
教主千秋万载,一桶浆糊

7

主题

82

帖子

110

积分

注册会员

Rank: 2

积分
110
QQ
 楼主| 发表于 2007-9-28 20:46:00 | 显示全部楼层

Re:游戏服务器技术交流

sjinny的command队列与事件队列其实也无多少区别吧,只是command封装的更好些,事件只是个简单通知

6377同学一直在说只看看,但似乎又想说点什么,难道是要我弄点排场来请一下?

bigbook2000说的不使用事件通知而使用switch-case,这应该算是编码习惯问题吧,本身event也好,signal也好,observer也好,就是为了模块间解耦,用switch-case当然什么都能解决,但似乎揉的太紧了

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2007-9-28 22:09:00 | 显示全部楼层

Re:游戏服务器技术交流

我那个只是跟大家分享一下,呵呵

0

主题

172

帖子

176

积分

注册会员

Rank: 2

积分
176
发表于 2007-9-28 22:27:00 | 显示全部楼层

Re:游戏服务器技术交流

swich case
到了逻辑复杂时,写死人的说。。。。

我习惯大分类用switch case,然后再逻辑层到Obj的消息定位的则FastDelegate

0

主题

172

帖子

176

积分

注册会员

Rank: 2

积分
176
发表于 2007-9-28 22:34:00 | 显示全部楼层

Re: 游戏服务器技术交流

补段代码,呵呵

  1. enum EVETYPE_KIND
  2. {
  3.         EVETYPE_UNKNOW = 0,                        //未知
  4.         EVETYPE_EVE = 1,                        //标准Event
  5.         EVETYPE_NET = 2,                        //网络函数
  6.         EVETYPE_SVR = 3,                        //服务响应函数
  7.         EVETYPE_SVRETOK = 4,                //服务调用成功返回
  8.         EVETYPE_SVRETERR = 5
  9. };

  10. //Event返回类型
  11. enum EVERET_KIND
  12. {
  13.         EVERET_OBJERR = -1,                        //目标错误
  14.         EVERET_CMDERR = -2,                        //函数名错误
  15.         EVERET_CMDKINDERR = -3,                //函数类型不匹配
  16.         EVERET_AGVERR = -4,                        //参数错误
  17.         EVERET_OK = 0,                                //调用成功,无返回值
  18.         EVERET_ASYN = 1,                        //调用成功,加入异步队列
  19.         EVERET_OKAGV = 2                        //调用成功,有返回值
  20. };

  21. typedef fastdelegate::FastDelegate1<CVar&,EVERET_KIND> type_EventFunc;
  22. typedef fastdelegate::FastDelegate2<CVar&,CVar&,EVERET_KIND> type_SvrCallRetOkFunc;
  23. typedef fastdelegate::FastDelegate3<int,CString,CVar&,EVERET_KIND> type_SvrCallRetErrFunc;

  24. typedef struct _tagEVEInfo
  25. {
  26.         EVETYPE_KIND        m_EVEKind;
  27.         U32I                        m_nEVEID;
  28.         CString                        m_sEventName;
  29.         CString                        m_sEventInfo;
  30.         _tagEVEInfo(void):m_EVEKind(EVETYPE_UNKNOW){}
  31.         _tagEVEInfo(const _tagEVEInfo &rhs)
  32.                 :        m_EVEKind(rhs.m_EVEKind),m_nEVEID(rhs.m_nEVEID),
  33.                         m_sEventName(rhs.m_sEventName),m_sEventInfo(rhs.m_sEventInfo)
  34.         {
  35.         }
  36. }tagEVEInfo;

  37. typedef struct _tagEvent
  38. {
  39.         tagEVEInfo* m_pEveInfo;
  40.         type_EventFunc  m_EventFunc;
  41. }tagEvent;

复制代码

18

主题

631

帖子

660

积分

高级会员

Rank: 4

积分
660
发表于 2007-9-29 08:35:00 | 显示全部楼层

Re:游戏服务器技术交流

哦?EVEmu的?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-25 23:20

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表