【问题标题】:Fast text parser for server-client messages - MMO服务器-客户端消息的快速文本解析器 - MMO
【发布时间】:2012-01-14 23:46:23
【问题描述】:

应用程序

我正在开发一款 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]}rot={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 或实时在线游戏中,客户端和服务器之间打包和读取消息的标准方法是什么?

【问题讨论】:

  • 很高兴你接受了我的回答,但我仍然想听听你最后做了什么以及是否有帮助。
  • @Groo 我想我会根据你提出的建议优化我的解析器;如果有的话,这是一个很好的做法。在我崩溃和燃烧的机会中,我可能会尝试 JSON。我真的不想仅仅因为我对它不满意而进行序列化,而且这似乎有点矫枉过正。
  • 我实际上将 此优化 称为矫枉过正,而只是抓住protobuf-net 并调用它的Serialize/Deserialize 方法。但我同意这是一个很好的做法,我可能也会这样做,只是为了看看我能剃掉多少个时钟。尽管如此,由于 protobuf 是二进制的,它会更好地打包数据并可能增加吞吐量,因此即使您对代码感到满意,也值得检查一次。 @tzaman 还提供了一些非常有趣的替代方案,其中一些我以前从未听说过。

标签: c# performance message text-parsing mmo


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      还有很多其他选项。 Here是一些比较。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-09
        • 2012-12-05
        • 1970-01-01
        • 2013-05-01
        • 2011-12-07
        • 1970-01-01
        相关资源
        最近更新 更多