【问题标题】:Generating identical pseudorandom numbers on client and server在客户端和服务器上生成相同的伪随机数
【发布时间】:2022-12-09 13:56:04
【问题描述】:

我有一个 Web 应用程序,在客户端使用 JavaScript,在服务器端使用 C#。我需要能够生成一组伪随机数 - 给定一个共享种子 - 在客户端和服务器端是相同的。有这样做的标准方法吗?显然,为各自的语言使用内置的 PRNG 库是不好的,因为它们的算法会有所不同。

我不想使用服务器端点为客户端提供随机数,因为我的客户端应用程序需要快速响应,这会增加延迟。它会工作但不会很理想。

【问题讨论】:

  • 为什么服务器不返回那些随机数?那么就没有必要生成它们两次并希望它们相同。
  • 表现。避免客户端不得不反复访问服务器。我正在编写一个需要快速响应时间的游戏,所以如果客户端可以生成服务器想要的内容而不是必须实际询问服务器,那就更好了,
  • 你可以写一个LCG,两边的因子相同。
  • @Jez:好吧,那我不明白为什么服务器也需要生成它。如果需要,客户不能提供吗?
  • @TimSchmelter 客户端很容易被修改,因此玩家可以生成他们想要给自己带来优势的任何数字。服务器需要自己独立生成随机数,以确保实际使用了正确的算法。

标签: javascript c# random


【解决方案1】:

在 c# 中的服务器上添加一个 API 端点以返回单个或一组随机数,然后从客户端调用它。

对服务器的调用不一定是低效的,这取决于您的逻辑和调用频率,从服务器调用它甚至可能有意义,特别是如果值的一致性非常重要,这可能是一个@987654321 @,调用频率是多少,您可以容忍的最高延迟是多少,以及您从实施中记录的响应时间类型。

是的,对于这样的问题(在客户端和服务器中复制逻辑)有一个标准的解决方案,那就是使用相同的随机数生成器算法和相同的种子价值。例如,这就是我们如何重玩纸牌游戏中的特定手牌。

允许您在客户端和服务器中使用相同代码的纯 C# 解决方案是考虑使用 Blazor 而不是 javascript。其他解决方案是实现您自己的算法或找到另一个已移植到 C# 和 javascript 的算法。

【讨论】:

  • 是的,我考虑过,但它需要客户端经常去服务器获取随机数,所以在性能方面,我宁愿避免客户端必须明确地从服务器获取它们。
  • 所以返回一个相当长的数组来减少这个。 Blazor 是一个合法的解决方案,因为它在客户端和服务器中是相同的随机逻辑......但是如果数字是在客户端生成的,为什么还要服务器呢?
  • 客户端很容易被修改,因此玩家可以生成他们想要给自己带来优势的任何数字。服务器需要自己独立生成随机数,以确保实际使用了正确的算法。
【解决方案2】:

这是 xorshift128+ 的 C 版本的 javascript 实现。根据维基百科文章,xorshift128+ 伪随机数生成器 (PRNG) 通过了 BigCrush(经验随机性测试)。

请注意,xorshift128+ 在实现 Math.random 时被主流浏览器使用,因此它是一个可靠的算法,虽然不是网络可靠的......

class XorShift128 {

  #state;
  
  static bitMask64 = ( 1n << 64n ) - 1n;
  static bitMask32 = ( 1n << 32n ) - 1n
  
  constructor( uint128Seed ) {
    this.#state = new BigUint64Array( [ ( uint128Seed >> 64n ) & XorShift128.bitMask64, uint128Seed & XorShift128.bitMask64 ] );
  }
  
  get nextValue() {
    let t = this.#state[ 0 ];
    let s = this.#state[ 1 ];
    this.#state[ 0 ] = s;
    t ^= t << 23n;
    t ^= t >> 18n;
    t ^= s ^ ( s >> 5n );
    this.#state[ 1 ] = t;
    return t + s;
  }

}

console.log( `Set the seed arbitrarily to 0x8a5cd789635d2dff121fd2155c472f96n and generate 5 values...` );
let PRNG0 = new XorShift128( 0x8a5cd789635d2dff121fd2155c472f96n );
for ( let i = 0; i < 5; i++ ) {
  console.log( ( PRNG0.nextValue & XorShift128.bitMask32 ).toString() );
}

console.log( `Let's do it again...` );

let PRNG1 = new XorShift128( 0x8a5cd789635d2dff121fd2155c472f96n );
for ( let i = 0; i < 5; i++ ) {
  console.log( ( PRNG1.nextValue & XorShift128.bitMask32 ).toString() );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-03
    • 2013-08-06
    • 1970-01-01
    • 2023-03-18
    • 2014-11-19
    • 2017-05-26
    • 2012-05-19
    • 1970-01-01
    相关资源
    最近更新 更多