2

应用

我正在开发 MMO,但遇到了问题。我构建的 MMO 服务器速度很快,并且在 UDP 套接字上每隔约 50 毫秒在本地向我的游戏客户端发送消息。这是通过我当前的消息系统从服务器到客户端的消息示例:

count={2}body={[t={agt}id={42231}pos={[50.40142117456183,146.3123192153775]}rot={200.0},t={agt}id={4946}pos={[65.83051652925558, 495.25839757504866]}腐烂={187.0}}

count={2}, 2 = number of objects
[,] = array of objects

我构建了一个简单的文本解析器,代码:http ://tinypaste.com/af3fb928

我使用如下消息:

    int objects = int.Parse(UTL.Parser.DecodeMessage("count", message));
    string body = UTL.Parser.DecodeMessage("body", message);
    for (int i = 0; i < objects; i++)
    {
        string objectStr = UTL.Parser.DecodeMessage("[" + i + "]", body);
        // parse objecStr with UTL.Parser.DecodeMessage to extract pos & rot and apply to objects
    )

问题

当我有更多对象〜60+时,性能会急剧下降。

问题

在 MMO 或实时在线游戏中,客户端和服务器之间打包和读取消息的标准方法是什么?

4

3 回答 3

2

二进制协议在这里会快得多。以您传入的坐标为例。当您将它们作为字节传输时,它们将占用每个轴 8 个字节,而字符串表示使用每个字符2 个字节(除非您传输为 ASCII,但即使这样,二进制双精度值也会更小)。

然后实际上将该字符串转换为数字需要更多的工作;首先必须创建一个子字符串,稍后会产生垃圾收集开销,必须解析这个数字,这并不快(但公平地说,您仍然可以每秒解析数十万个双精度数),因为 .NETdouble.Parse非常通用并且必须适应许多不同的格式。如果您坚持使用文本,您将通过编写自己的双解析器获得显着的速度,但就像我说的,如果消息解析是一个瓶颈,您应该使用二进制。将字节转换为双精度(使用一点unsafe魔法,如果您正在运行服务器并且应该具有完全信任模式,这应该没问题)是复制 8 个字节的问题。

如果您的消息大多只是坐标等,我认为您可以通过创建自己的二进制格式来获得很多。

于 2013-06-18T17:22:35.667 回答
1

我会考虑使用像Thrift这样的 RPC 框架来为您完成提升工作。它会为您进行打包和解析,并通过网络以二进制形式发送内容,因此效率更高。

还有很多其他选择。这里有一些比较。

于 2012-01-14T23:55:27.770 回答
1

您的问题之一可能是不必要的字符串实例化。每当您进行连接、拆分或获取子字符串时,您都会在堆栈上创建新的字符串实例,这些实例是从原始字符串复制的,之后需要收集。

尝试更改代码以逐个字符地遍历字符串,并仅使用原始字符串解析数据。您应该只使用索引,indexOf甚至可能编写自己的 int 和 float 解析器,它们接受字符串偏移量 + 长度以避免创建子字符串。我不确定这是否矫枉过正,但如果您有确凿的证据表明它运行缓慢,则它不是“过早的”优化。

另外,您是否尝试过协议缓冲区?我相信他们的表现应该相当不错(只需编写一个小型控制台应用程序进行基准测试)。或者使用 JSON,这是一种标准的简洁格式(但我不知道 Json.NET 的优化程度如何)。就性能而言,通常没有什么比硬编码的专用解析器更胜一筹,但考虑到未来的维护,我会先尝试其中一种协议。

于 2012-01-15T00:00:40.137 回答