1

当我为一个简单的客户端<>服务器多人游戏编写一个简单的服务器时,我想到了以下使用翻译库的基于文本的协议。基本上,每个命令都有一定的含义,例如:

1 = character starts turning right
2 = character starts turning left
3 = character stops turning
4 = character starts moving forward
5 = character stops moving
6 = character teleports to x, y

因此,客户端将简单地广播以下内容以通知玩家现在正在向前移动并向右转:

4
1

或者,传送到 100x200:

6#100#200

其中 # 是参数分隔符。

套接字连接将连接到玩家标识符,因此无需使用协议广播标识符即可知道消息属于哪个玩家。

当然,所有数据都将在服务器端进行验证,但这是一个不同的主题。

现在,这对我来说似乎非常有效,只有 2 个字节来通知服务器我正在前进并右转。

但是,我看到的大多数“专业”代码片段似乎都在发送对象或 xml 命令。这对我来说似乎需要更多的服务器资源,不是吗?

为什么我的基于文本的协议会高效,我没有经验的逻辑是有缺陷的吗?或者实时动作多人游戏的推荐协议是什么?

我想设置一个尽可能高效的协议,因为我不想使用多个集群/服务器来覆盖我的 2D 多人游戏的过多带宽,以及安全同步问题和麻烦。

4

4 回答 4

4

您需要了解发送数据所涉及的延迟。如果接收这些数据包之间的时间与发送它们之间的时间不同,“开始转向”/“停止转向”将不太有效。

我不能代表所有游戏,但是当我编写此类代码时,我们会通过网络发送方向和位置信息。这样,接收器可以进行平滑和外推(根据我拥有的已知旧数据找出对象应该“现在”的位置)。不同的游戏会想要发送不同的数据,但一般来说,您需要弄清楚如何使接收方的数据显示与发送方的一致,因此您需要在面对网络问题时发送具有弹性的数据。

此外,许多游戏使用 UDP 而非 TCP 进行此类数据传输。UDP 不可靠,因此您可能无法获得所有数据包。这意味着“现在停止移动”或“现在开始移动”可能不会成对接收。在 UDP 上编码时,更重要的是每隔一段时间发送“这是现在的状态”,以便客户端有足够的机会同步。

于 2010-05-04T17:51:55.540 回答
4

但是,我看到的大多数“专业”代码片段似乎都在发送对象或 xml 命令。这对我来说似乎需要更多的服务器资源,不是吗?

为什么我的基于文本的协议会高效,我没有经验的逻辑是有缺陷的吗?或者实时动作多人游戏的推荐协议是什么?

发送纯文本比发送包含相同信息的二进制格式更昂贵。例如,如果您只发送 1 个字节,则只能发送 10 个不同的命令,数字 0 到 9。二进制格式可以发送尽可能多的不同命令,因为您可以将不同的值放入一个字节中,即。256.

因此,尽管您认为对象很大,但实际上它们几乎总是小于同一对象的纯文本表示。通常它们在没有压缩的情况下尽可能小(无论如何你都可以添加压缩)。

纯文本格式的好处是它们易于调试和理解。不幸的是,如果您将自己的编码放在那里(例如,将命令减少到单个数字而不是可读名称),您将失去这些好处。缺点是格式更大,并且您必须编写自己的解析器。XML 格式消除了第二个问题,但它们无法与二进制格式竞争纯粹的效率。

但是,您可能在这个阶段过度考虑了这个问题。如果您只发送有关事件的信息,例如您上面提到的命令,那么带宽将不是问题。它正在广播有关游戏状态的信息,这可能会变得很昂贵 - 但即使是这种情况也可以通过小心发送给谁以及发送频率来减轻。我建议现在使用最简单的任何格式,因为这将是您遇到的最少的问题。只需确保您的代码始终处于您可以在以后需要时更改消息写入和读取例程的状态。

于 2010-05-05T16:29:49.050 回答
3

常见的方法是使用二进制格式,而不是文本,而不是 xml。因此,只需一个字节,您就可以表示 256 个不同命令之一。

还要使用 UDP 而不是 TCP。在丢包的情况下,使用 UDP 游戏的响应速度会更快。如果数据包丢失,您仍然可以推断运动。为每个数据包发送一个数据包编号,以便服务器知道何时发送命令。

我强烈建议您下载Quake 源代码,您可以在其中了解有关现代多人游戏中网络编程的更多信息。这真的很容易阅读和理解。

编辑:

我差点忘了.. Google 的Protocol Buffers在发送复杂的数据结构时会很有帮助。

于 2010-05-04T18:30:10.780 回答
1

我想我会给我两分钱,并为所谓的二进制序列化提供一个实际应用程序。这个概念实际上非常简单,但只是表面上看起来很复杂。

您实际上可以发送 XML 并拥有一个服务器,该服务器将 XML 中的数据处理到服务器本身的不同功能。您也可以只向服务器发送一个数字,该数字作为变量存储在服务器中。之后,它可以处理其余数据并选择正确的行动方案。

例如,一些粗略的代码:

private const MOVE_RIGHT:int = 0; 
private const MOVE_LEFT:int = 1;
private const MOVE_UP:int = 2;
private const MOVE_DOWN:int = 3;

function processData(e:event.data)
{
    switch (e)
    {
       case MOVE_RIGHT:
       //move the clients player to the right

       case MOVE_LEFT:
       //move the clients player to the left

       case MOVE_UP:
       //move the clients player to the up

       case MOVE_DOWN:
       //move the clients player to the down

    }
}

这将是一个非常简单的示例,需要进行修改,但正如您所看到的,您只需存储使用整数编码的变量,这些变量以数字字符串的形式传输。您可以解析这些并创建信息标题,以将它们组织成需要传输的不同数据部分。

此外,最好为游戏进行 UDP 设置,因为仅仅丢失一个数据包不应该阻碍游戏体验,而是应该能够在客户端和服务器端处理它。

于 2011-06-21T06:57:31.653 回答