以秒精度计时用户任务

时间:2011-07-18 01:30:36

标签: timer synchronization client-server client-side server-side

我正在构建一个网站,我需要对用户的任务进行计时,向他们展示时间,并跟踪他们完成任务需要多长时间。计时器应该精确到秒,整个任务应该需要大约3-4小时 我还应该阻止用户伪造完成时间(没有涉及金钱,所以它不是真正的高风险,但存在一些风险)。

目前我使用时间戳来跟踪用户何时开始,同时初始化基于JS的计时器,当用户完成我收到通知时,我计算当前时间和开始时间戳之间的差异 - 这种方法不好,用户的计时器和我的时差之间有几秒的差异(即我计算的时间花了用户完成任务,注意:这只是在我的开发环境中测试过,因为我还没有任何其他环境..) 我考虑的另外两种方法是:
1.完全依赖客户端计时器(即JS),当用户完成任务时 - 发送加密时间(这样用户不能伪造开始时间)。这似乎不太实际,因为我无法想出一种在客户端生成秘密密钥的方法,这将是“秘密”。
2.完全依赖服务器端计时器,每秒发送“滴答”。与其他两种方法相比,这似乎是很多的服务器端工作(机器,而不是人类......例如,为每个“tick”访问数据库以获得开始时间),而且我也不是确定它完全准确。

修改
以下是算法措辞中正在发生的事情:

  1. 用户启动任务 - 服务器向用户发送任务ID并在db记录开始时间,初始化客户端计时器。
  2. 用户完成任务,他的计时器正在运行......
  3. 用户结束任务,停止计时器,并将用户的答案和任务ID发送到服务器。
  4. 服务器检索开始时间(使用收到的任务ID)并计算用户完成任务所需的时间。
  5. 问题 - 服务器计算的时间,客户端显示的时间不同。

    非常感谢任何见解。

5 个答案:

答案 0 :(得分:2)

我认为这会奏效。好像你有同步问题和加密问题。我的建议是以一种对用户不可见的方式解决同步问题,同时仍保持安全性。

想法:计算并显示滴答客户端,但使用加密技术来阻止用户发送伪造的时间。只要用户报告的时间接近服务器的测量时间,只需使用用户的时间。否则,要求伪造。

  1. 客户端要求服务器执行任务。

  2. 服务器获取当前时间戳,并使用自己的公钥对其进行加密。这将与任务一起发送回客户端(可以是纯文本)。

  3. 客户端工作直到完成。 Ticks在本地记录。

  4. 客户端完成并向服务器发回其答案,它所记录的滴答数以及服务器首次发送的加密时间戳。

  5. 服务器解密时间戳,并将其与当前本地时间进行比较,以获得多个滴答。

  6. 如果服务器计算的刻度数在某个容差范围内(例如10秒,为了安全起见),服务器会接受用户报告的时间。否则,它知道时间是伪造的。

  7. 由于用户的时间被接受(只要在合理范围内),用户永远不会知道服务器时间可能与他们报告的时间不同步。由于您跟踪的时间段很长,因此丢失几秒钟的精确度似乎不会成为一个问题。该方法仅需要加密单个时间戳,因此它应该很快。

答案 1 :(得分:2)

如果我已经正确理解了问题,那么服务器和客户端的时间会略有不同,而且总是如此。

所以我稍微调整一下您的原始序列如下:

  1. 用户启动任务 - 服务器向用户发送任务ID并记录开始 在db的时间,客户端计时器被初始化。
  2. 用户客户端通知服务器客户端启动时间;记录在DB中 与服务器启动时间一起
  3. 用户完成任务,他的计时器正在运行......
  4. 用户结束任务,计时器停止,用户经过时间,回答 和任务ID被发送到服务器。
  5. 收到后,服务器会记录传入的请求时间,然后进行检索 开始时间计算用户完成任务所需的时间 服务器时间(开始/结束)和客户端时间。
  6. 服务器确保客户端值在可接受的范围内 服务器验证时间并使用客户端时间。如果是客户 时间不在可接受的范围内(例如30秒),然后使用服务器时间作为 图。
  7. 由于延迟,服务器负载等原因,时间会略有不同。因此,通过使用客户端值,它将更加准确,同样安全,因为这些值经过了检查。


    回答评论:

    您只能拥有一种准确性,无论是客户/用户看到的准确度,还是服务器知道的准确度。来自客户端的任何东西都可能被污染,因此必须在某处进行妥协。您可以通过测量和偏移来最小化这一点,使得结束差异与起始差异在同一范围内,使用服务器时间,但它永远不会100%不可更改。如果确实存在这么多问题,那么存储时间会更准确。

    如果你真的必须具备准确性和可靠性,那么唯一的方法是使用服务器时间并定期通过ajax获取它以进行显示,并使用本地计时器通过实际报告时间和报告时间之间的滑动调整算法填补空白。

答案 2 :(得分:1)

防止作弊的唯一方法是不要完全信任客户端,而只是计算服务器上的最终时间,作为从发送任务到客户端之前到接收之间的时间结果。

这也意味着最后一次必须包含一些网络传输延迟,这看起来不公平:如果你试图以某种方式对它们进行补偿,客户端总是会假装患有比实际更多的延迟。

但是,您可以尝试确保网络延迟不会让用户感到意外。下面是一个简单的方法,它可以完全防止作弊,同时考虑到一些关于时钟速率和网络延迟的温和假设,在提交结果时客户端显示的运行时间应与服务器上计算的最终时间大致相符:

  1. 客户端启动计时器并从服务器请求任务。
  2. 服务器记录当前时间并将任务发送给客户端。
  3. 用户完成任务。
  4. 客户端将结果发送到服务器并(可选)停止计时器。
  5. 服务器接受结果并从当前时间减去步骤2中保存的时间戳以获得最终时间。
  6. 服务器将最终时间发送回客户端。
  7. 这里的技巧是在从服务器请求任务之前启动客户端时钟。假设步骤1和2以及步骤4和5之间的单向网络传输延迟大致相同(并且客户端和服务器时钟以大致相同的速率运行,即使它们不同步),时间也是如此在客户端计算的步骤1到4应该与从步骤2到5在服务器上计算的时间相匹配。

    从心理学的角度来看,将客户端时钟保持在第4步之后可能是个好主意,直​​到从服务器收到最后一次。这样,当运行时钟被最后时间替换时,跳跃很可能是倒退,使得用户比时间稍微向前跳跃更快乐。

答案 3 :(得分:0)

阻止客户端伪造时间戳的最好方法就是永远不要让他们有权访问它。使用用户启动时服务器生成的时间戳。您可以将其存储在服务器的RAM中,但将其写入数据库可能会更好。然后,当客户端完成任务时,它会让服务器知道,然后将结束时间戳写入数据库。

这里您需要的重要信息似乎是开始和结束时间的差异,而不是实际的开始和结束时间。如果那些时间 重要,那么你肯定应该使用单个设备的时间跟踪机制,即服务器的时间。由于时区的不同,依靠客户的时间使他们无法相互比较。此外,最终用户很容易捏造他们的时间(意外或故意)。

底线:这里会有一些不准确之处。当您需要满足如此多的要求时,您必须妥协。希望这个解决方案能给你最好的结果。

答案 4 :(得分:0)

时钟同步

这就是你要找的,WikiPedia explanation

And here is the solution for JavaScript.