【问题标题】:How to know when a tcp message was sent如何知道何时发送了 tcp 消息
【发布时间】:2014-09-01 22:22:52
【问题描述】:

在一个类似农场的在线游戏中,我需要验证服务器客户端的漫长过程,比如建造房屋。假设建造房子需要 10 分钟。客户端在开始建造房屋时通过 TCP 连接异步发送“开始建造”消息,并在认为房屋建造时发送“完成建造”消息。在服务器上,我需要验证房子是在至少 10 分钟内建成的。问题是服务器不知道客户端何时发送“开始构建”和“完成构建”消息。它知道何时收到消息,但存在网络延迟,可能的网络故障和消息可能足够长以占用几个 tcp 段。据我了解,客户端发送消息所花费的时间可能长达几分钟,并且取决于客户端 TCP 配置。问题是:有没有办法知道消息何时在客户端发出?如果不是,我如何保证该消息的发送时间段,可能是一些服务器 TCP 配置?该服务器中的一些超时要么接收消息,要么失败。任何其他我可能没有想到的主要任务的解决方案也是受欢迎的。

提前致谢!

【问题讨论】:

  • 为什么还要关心这个?你知道什么时候开始建房子,让服务器在 10 分钟后向客户端发送消息。
  • 房屋建造可以中断和/或其他工作速度不同的工人可以稍后开始建造。对于用户来说,它应该看起来尽可能流畅,服务器的构建时间没有变化,所以服务器只做乐观的验证,让客户端欺骗而不是惩罚诚实的客户端。我不希望服务器运行单独的任务来确定何时向可能不再连接的客户端发送“完成构建”的另一个原因。如果没有其他选择,我可能会不得不做类似的事情,但我想先寻找一种方法来限制客户端滞后模糊性。
  • 如果您只是想减少延迟并且不打扰客户作弊。我会推荐使用 UDP,因为在大多数情况下它是真正异步的并且比 TCP 更快。由于您不想传输文件而是传输非常短的消息,因此它可能最适合您的游戏(就像大多数其他多人游戏一样)。
  • UDP 也有同样的问题,甚至更糟 - 有了它,我什至不知道是否发送了消息,不仅仅是发送时间。

标签: sockets tcp client-server validation


【解决方案1】:

如果我的理解正确,您的主要问题与 TCP 本身无关(因为所描述的场景也可能使用 UDP 发生),而是与您的消息的时间顺序以及确保时间线没有被伪造有关。

因此,您要避免的唯一情况是:

STARTED send at 09:00:00 and received at 09:00:30 (higher latency)
FINISHED send at 09:10:00 and received at 09:10:01 (lower latency)

在服务器看来,构建您的虚拟建筑只需要 9.5 分钟。但客户端并没有作弊,只是第一条消息的延迟比第二条高。

反之亦然:

STARTED send at 09:00:00 and received at 09:00:01 (lower latency)
FINISHED send at 09:10:00 and received at 09:10:30 (higher latency)

STARTED send at 09:00:00 and received at 09:00:10 (equal latency)
FINISHED send at 09:10:00 and received at 09:10:10 (equal latency)

在收到两条消息之间至少间隔了 10 分钟。

不幸的是,没有办法确保客户端不会通过使用时间戳等方式作弊。无论您的客户端是否在消息中写入时间戳或协议是否为您执行此操作,都无关紧要。有两个原因:

  • 即使您的客户端没有作弊,客户端的系统时钟和 服务器可能不同步
  • 网络数据包中写入的所有数据都只是字节,可以进行操作。有人可以使用 RAW 套接字并伪造整个 TCP 层

所以唯一可以确定的是服务器接收到消息的时间。如果服务器认为收到 FINISHED 消息时没有足够的时间过去,一个简单的解决方案是向客户端发送某种包含剩余时间的 RETRY 消息。所以客户端可以调整构建动画,然后根据剩余的时间再次发送 FINISHED 消息。

【讨论】:

  • 问题与您描述的完全一样 - 感谢我没有提供的精美插图。服务器只看到接收消息的时间,它可以小于或大于客户端发送的消息之间的时间。是的,服务器只能验证这个接收时间,任何时间戳都可以伪造。
  • 我已经考虑了 RETRY 解决方案,它需要一些客户端逻辑和回滚用户可以看到我们试图避免的。比起强迫普通客户端重绘游戏或回滚进度,我会更好地原谅稍微作弊的客户端。
  • 问题是什么时候我必须原谅。在您的示例中只有 30 秒,但请参阅 pcvr.nl/tcpip/tcp_time.htm#21_2 这本书说 9 分钟!所以问题是我该如何管理这段时间并将其减少到 1 分钟?据我了解,套接字超时不起作用,因为客户端可以每 1 分钟发送一次小消息块,而整个消息仍需要几分钟才能传递。
  • 您可以为回滚设置动画,这样没人会注意到。但是比 RETRY 消息更好的是使用 UDP 协议,这应该可以减少你的延迟,如果延迟在几分钟的数量级,游戏将不再有趣,所以这是一个你无法解决的问题软件,是由中间的网络引起的。
猜你喜欢
  • 1970-01-01
  • 2012-12-11
  • 1970-01-01
  • 2020-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 2012-02-03
相关资源
最近更新 更多