【问题标题】:GAMEPROGRAMMING Client/Server communication through .... ? (JAVA)GAMEPROGRAMMING 客户端/服务器通过 .... 通信? (JAVA)
【发布时间】:2013-08-08 23:18:52
【问题描述】:

我有一个关于在网络游戏中对客户端/服务器通信进行编程的一般性问题。 我使用 TCP 作为协议,并且通信......有效,但我不确定它是否是一种有效的方式。

一般来说,发生在客户端的动作都会经过所有这些步骤:

  1. 一些动作(例如,一个火球被施放)
  2. [*]对于这个动作,我定义了一个字符串(例如#F#270#130#,这意味着“F”表示它是一个火球,而 270 是(例如)角度的度数,130 -射击的火球的速度。)
  3. 字符串进入客户端的 outputpuffer 和等待队列
  4. 字符串已发送
  5. 服务器接收到字符串
  6. [*] 服务器需要一个可以检测字符串含义的行解释器(这里:F 是什么意思?它是一个火球!)并添加一个唯一标识,基于从哪个客户端接收命令。李>
  7. [*]服务器需要根据发生的动作计算逻辑(火球对某人造成伤害,它是(立即)击中某人还是先飞?)
  8. 服务器向所有客户端发送一个(更新的)操作字符串。 (例如,可能由于某种原因火球的速度变慢了 - 这里将更新字符串(#F#12345#270#90# - 12345 是唯一的玩家身份)
  9. 客户端接收字符串
  10. [*] 客户端将字符串解析为命令 + 处理它(触发动画序列...)
  11. 最初发送命令的客户端将接收到的字符串与waitingqueue中的字符串进行比较 - 当相等时,什么都不做(平滑一些动作,否则由于连接问题/延迟,一些动作会发生两次或从一个位置跳转到另一个位置,基于ping

真的有必要完成所有这些步骤吗?在标有 [*] 的所有步骤中,我需要为每个命令定义新的 lineinterpreters/action,因此我将每个操作编码两次,客户端和服务器端。 我读过一些关于发送可序列化对象的文章,但总的来说,这个想法对我来说似乎是一样的,我发送一个对象,它必须被解释+处理,然后我发回一个对象......

有什么提示吗?用更少的编码解决整个通信更优雅?或者更有序 - 所有这些用于不同操作的 #F# #M# #H# 标记使其变得越来越复杂:)

(事实上,我实际上有以下处理程序/操作:

-移动 -看/旋转 -hpchange -火箭 -spawn/断开连接 ...)

希望你明白我的意思 - 我知道,我可以继续这样编码,它会以某种方式工作,但它似乎太复杂了。

谢谢!

【问题讨论】:

  • 还有更多:) 发送字符串,传输字节到服务器,服务器接收字符串,以及其他你没有提到的100个步骤

标签: java tcp client communication serializable


【解决方案1】:

如果您满足以下条件,您可以采用更面向对象的方式:

  1. 定义一个名为 Action 或类似的对象,它具有上述所有参数 - 动作类型、动作方向(或 目标)、造成的伤害等。
  2. 在游戏正常执行时创建那些 Action 对象
  3. 使用链接到 TPC Socket 的 ObjectOutputStream 将整个 Action 对象输出到服务器/将其传递回客户端。
  4. 在服务器上,通过检查从 ObjectInputStream 接收到的对象来解释发生了什么。

如果您添加更多逻辑,我认为这种方式会更干净、更灵活,而不仅仅是分析字符串,但速度不会那么快(因为进入 ObjectOutputStream 的对象需要被序列化)。

【讨论】:

  • 好的,这听起来像是我读过的。但是,是的,那会更优雅:) 我想我会将我的代码编辑为这个变体并定义一个抽象动作类,以及许多将描述动作的子动作类......是否可以在类中定义方法,铁doLogic() 然后在被发送到服务器并返回后,调用它们?例如。 action.doLogic() 这些会更新游戏的一些参数吗?这将非常有帮助! ^^
  • 是的,它可以定义方法,基本上你可以传递任何普通类,只要它没有对外部东西的引用 - 例如。对文件或数据库等的引用……如果是这样,那些表示引用的实例变量必须用修饰符瞬态进行标记,这样它们就不会被序列化。您可以在此处阅读有关何时使用瞬态的更多信息:stackoverflow.com/questions/5960280/… 希望对您有所帮助,祝您好运!
【解决方案2】:

在决定您的游戏是否需要任何更改之前,您需要考虑几个因素。

首先,TCP 是不是最好的通信渠道?您是否将其与UDP进行了比较。使用UDP实现网络会更好吗?如果丢失了一些数据包会很重要吗?网速慢怎么办?

其次,查看您轮询/推送到服务器的频率。这可以减少吗?游戏必须是实时的。游戏的所有部分都必须是实时的。也许某些事情可能是非实时的。火球会沿着直线前进,所以你不必不断更新服务器关于它的位置,你可以告诉它它的方向和速度。游戏的哪些其他方面可以是非实时的。唯一需要发送的是玩家位置和动作。大多数其他事情,如碰撞检测,都可以卸载到客户端。

第三,是否每次按键都需要发送到服务器?如果用户靠墙并想进一步移动,则客户端知道他们不能,因此不会将这些按键发送到服务器。如果用户已移动到新的有效位置,则更新服务器。是否可以一次性缓冲某些内容并将其发送到服务器,而不是向服务器发送多个查询。即,如果我向前移动,跳跃并扔一个火球,那就是客户端的 3 次按键,它们可以在接下来的第 500 毫秒被缓冲和发送吗?

如果您担心网络开销,您应该在位级别工作。与其发送一个长字符串“#F#270#130#”——它有 11 个字节长,不如发送 3 个连续字节(24 位)。

7 位代表动作(127 个不同的动作)。 9 位将代表角度 (1-512),但您只需要 0-360 度。 8位代表力。

这种或任何其他字节格式更短,更易于在网络上使用,并且生成更紧凑的代码。二进制比较也更快,所以现在在服务器上编写你的动作解析器变得更容易了。 IE。您只需查看前 7 位并将其与 int 进行比较,而不是寻找 #F# 的大型开关盒。

您能否减少其他网络开销,而不是由客户端决定,服务器可以决定这一点。即标准力,或 2 级力(更好,因为这可以用 1 位表示)。这阻止了客户端和恶意用户向服务器发送垃圾数​​据(如 999 的强制),现在强制可以是 0 或 1,即 10 或 20 的速度,没什么傻的。

【讨论】:

  • 好的,谢谢,这听起来非常有用,据我所知,大多数著名的多人游戏(RealTimeStrategy...星际争霸?,不确定,但魔兽世界?)使用 UDP,但我不能想象一下如何处理丢失的信息,我的意思是,几乎每一个动作都很重要,或者可能很重要。每一个被送出的对象,都可能是一次濒死的治疗。我喜欢减少流量的部分,但我不认为我的小游戏会遇到交通繁忙的情况:D 它可以处理,不知道,可能多达 5 个玩家和约 50 个其他移动物体。目前,动作被缓冲在 50 毫秒的堆栈中......
  • 也许你的消息可以用几个字节代表一个消息ID。每个客户端都有自己的消息发送和接收队列,它们是顺序的,所以 00000001 和 00000010 等等不断增加(并最终重置),所以你可以跟踪。如果服务器或客户端曾经看到一条不按顺序排列的消息,它将知道一条消息在转换过程中丢失了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 2021-07-29
  • 2012-06-29
  • 1970-01-01
相关资源
最近更新 更多