当我为简单的客户编写一个简单的服务器<>服务器多人游戏,我想到了使用翻译库的以下基于文本的协议。基本上,每个命令都有一定的含义,例如:
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多人游戏的过多带宽,以及安全的同步问题和麻烦。
答案 0 :(得分:4)
您需要了解发送数据所涉及的延迟。如果收到这些数据包之间的时间与发送数据包之间的时间不同,则“开始转动”/“停止转动”将不太有效。
我不能代表所有游戏,但是当我处理这类代码时,我们会通过网络发送方向和位置信息。这样接收器就可以进行平滑和外推(根据我已经知道的旧数据,找出对象应该“现在”的位置)。不同的游戏会想要发送不同的数据,但一般来说,您需要弄清楚如何使接收者的数据显示与发送者的数据相匹配,因此您需要发送面对网络问题时具有弹性的数据。 / p>
此外,许多游戏使用UDP进行此类数据传输而不是TCP。 UDP不可靠,因此您可能无法获取所有数据包。这意味着“现在停止移动”或“现在开始移动”可能不会成对接收。在UDP之上进行编码时,每隔一段时间发送“现在就是状态”就更为重要,这样客户就可以获得充分的同步机会。
答案 1 :(得分:4)
然而,大多数“专业”代码 我看到的片段似乎在发送 对象或xml命令。这似乎是 需要更多的服务器资源 我,不是吗?
我的无经验逻辑是为什么我的 基于文本的协议将是有效的 有缺陷?或者推荐什么 用于实时行动的协议 多人游戏?
发送纯文本比包含相同信息的二进制格式更昂贵。例如,如果您只发送1个字节,则只能发送10个不同的命令,数字0到9.二进制格式可以发送尽可能多的不同命令,因为您可以将不同的值放入一个字节,即。 256。
因此,尽管您认为对象很大,但实际上它们几乎总是小于同一对象的纯文本表示。通常它们在没有压缩的情况下尽可能小(并且总是可以添加压缩)。
纯文本格式的好处是它们易于调试和理解。不幸的是,如果你在那里放置自己的编码,你会失去这些好处(例如,将命令减少到单个数字而不是可读名称)。缺点是格式更大,你必须编写自己的解析器。 XML格式消除了第二个问题,但它们无法与二进制格式竞争纯粹的效率。
然而,你可能在这个阶段过度思考这个问题。如果您只发送有关上述命令等事件的信息,则不会考虑带宽。它广播有关游戏状态的信息可能会变得昂贵 - 但即使这样也可以通过小心你发送给谁以及频率来减轻。我建议使用目前最简单的格式,因为这将是您遇到的最少问题。只需确保您的代码始终处于可以在以后更改消息编写和读取例程的状态。
答案 2 :(得分:3)
常见的方法是使用二进制格式,而不是文本,而不是xml。因此,只有一个字节,您可以表示256个不同命令之一。
也使用UDP而不是TCP。在数据包丢失的情况下,游戏对UDP的响应速度会更快。如果丢包,您仍然可以推断出运动。每个数据包发送一个数据包编号,以便服务器知道命令何时发送。
我强烈建议您下载Quake source code,以便在现代多人游戏中了解有关网络编程的更多信息。这很容易阅读和理解。
我差点忘了.. 在发送复杂数据结构时,Google Protocol Buffers可以提供很大帮助。
答案 3 :(得分: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设置,因为丢失数据包不应该暂停游戏体验,而应该能够处理客户端和服务器端。