« 精读《TCP/IP 详解》 | 返回首页 | Google 输入法 »

游戏服务器内的组播

游戏服务器在设计时,会有许多组播的需求。比如一个 NPC 需要向周围的观察者播出它的状态信息。无出不在的各种聊天频道中需要向频道中的参于者广播聊天消息等。

通常,我们会为每个组播的请求维护一张列表,然后再把需要的信息包发送给指定列表上的多个连接。这个过程在很多地方都会遇到,一个设计的不太好的引擎,再这里有可能滋生诸多 bug 。尤其在多服务器的设计时尤其如此。

这两天,我试图寻找一种简洁统一的解决方案。

前几天的一篇 blog 讨论了一组服务器设置多个外部接入点的设计。就着这个思路我们可以引申一下。

当每台连接服务器设置一个不大的上限,比如最多同时处理 8192 个外部连接,那么管理分组倒不会带来太大的负担。

我们只需要在逻辑服务器与连接服务器间定义四条协议。

  1. 把一个连接加入指定分组。
  2. 让一个连接退出指定分组。
  3. 向一个分组广播消息。
  4. 删除一个分组。

这里,后两条协议是冗余的。

对于第三条协议,如果表示连接号的容量足够大,我们完全可以留一部分号码用于组播。这在 IP 协议中定义 IP 地址的构成时就是用的类似方案。不过我们的设计为了节省带宽,全部用的 2 字节做内部连接号,资源比较紧张,所以就单独设计一条协议了。

对于第四条协议,当最后一个连接退出时,分组就自然取消了。增加一个专门的删除协议,纯粹是使用上的方便。

在连接服务器上维护一个分组,仅仅需要一个 1K 的数组(8192 bits)。而有组播需求时,只用遍历这个数组。在 32 位系统下,只是一个 256 次的循环而已。因为大部分分组的成员都不会太多。数组中充斥着大量的 0 。扫描一下就非常的快了。

连接服务器用一个简单的 freelist + hash 表的技术,就可以高效且动态的管理不限量的分组,无论从 CPU 还是内存的负载来看,都是可以接受的。

我们额外需要做的只是一个分组编号分配管理器。为每个进程分配唯一独立的分组号就够了。在我们现在的设计中,为了尽量避免交互通讯。分配新组号采用不需要反馈的形式。每个需要申请组号的进程,都有独立的组号 id 空间。由分组管理器对若干独立的分组号做一次统一映射。

换句话说,每个服务器进程都可以直接从 0 号分组用起,然后直接用 1 号,2 号,3 号 …… 类似操作系统管理物理内存一样。独立进程拥有的只是虚拟分组号,由管理器映射到全局唯一分组号上。这样就完美的解决了不同服务器进程间的分组编号冲突问题。

Comments

干脆不要聊天服务器, 让玩家自己连接在一起(同属一个队伍), 或者, 玩家想世界聊天, 就用贴广告的方式,把消息给服务器, 服务器定时处理这些广告, 根据每个消息在什么组来决定发送时间.
互联网上的纯协议层的组播协议的确是没啥前景,但是应用层的组播协议早就非常成熟了。
为什么要固定的分组呢? 如果要广播消息的话发送一个client list不就可以了么?多么简洁方便的方法。
那请问在这样的结构中逻辑服务器怎样才能将指定的连接加入到分组中呢,是不是每个连接都有一个标识号?逻辑服务器只要提供标识号就能将对应的连接加入到分组中?
Internet 上的多播目前是不可能实现的。 因为按目前的协议,都是自行发起加入某个编组,而没有一个统一的分组管理器。如果按这种协议在 Internet 上实现多播,每个 IGMP 包都会发到 Internet 的各个角落,这显然是不现实的。
多播需要路由支持。
对于聊天这一块,在一些公司做的时候大多通过服务器中转,但是为什么没有人用多播?这可是减少网络流量的绝好方法呀!
云凤大哥,不知道现在有没有研究CPU的多核技术,这个对将来的游戏服务器必然产生深远的影响。
比如一个分组有 ABCDEF 6 个人, ABC 在一号服务器上,DEF 在二号服务器上。那么这个分组则同时存在于一号和二号服务器。 在组播的时候,任何组播消息都完整的发到所有前端连接服务器。 当然,前端连接服务器不宜太多。在分组人数小于连接服务器时,带宽可能消耗的更多。
请问,这种设计,既然分组号在各个连接服务器进程上是独立的,那么同一个区域的人(属于同一分组)要是分布到不同的连接服务器上面,那么这个区域岂不是要对应于多个分组了吗?
就分组来说不会特别的。比如用分组来管理类似 AOI 的区域,极端情况也也很难超过四千个分组。(一共 8192 人,至少两人一组) 分组可以动态分配和回收,资源可以重复利用。32M 内存就可以提供三万多分组的管理,这对于 2G 的地址空间来说实在是很小的一个零头。
在连接服务器上维护一个分组就需要1k,那么很多分组是不是要很多k呢?

Post a comment

非这个主题相关的留言请到:留言本