【问题标题】:How to generate random 6 digit which expire after 5 second?如何生成 5 秒后过期的随机 6 位数字?
【发布时间】:2013-04-08 14:23:23
【问题描述】:

我有一个逻辑可以生成一个 6 位数字,该数字在 5 秒内保持不变。这是代码。问题是下面的例程按顺序生成数字,我不想要我想要动态的,任何用户都无法猜测下一个数字是什么。

public static int GetTimestamp()
{
    // 10m ticks in a second, so 50m in 5 seconds
    const int ticksIn5Seconds = 50000000;
    return (int)((DateTime.Now.Ticks / ticksIn5Seconds) % 1000000);
}

这里是另一个在 C# 中生成唯一 8 位数字的代码。

public string Get8Digits()
 {
   var bytes = new byte[4];
   var rng = RandomNumberGenerator.Create();
   rng.GetBytes(bytes);
   uint random = BitConverter.ToUInt32(bytes, 0) % 100000000;
   return String.Format("{0:D8}", random);
 }

我尝试结合这两种逻辑来生成随机的 6 位数字,可能无法猜到下一个 6 位数字会生成什么。寻求指导我应该怎么做才能实现我的目标。谢谢。

【问题讨论】:

  • 这个问题对我来说毫无意义。想要一个随机数?调用 Random 的 Next 方法。想要每 5 秒随机数一次?每 5 秒调用一次 Next。

标签: c#


【解决方案1】:

一种基于您自己的Get8Digits 方法的可能解决方案...

    private static DateTime _expiry = DateTime.MinValue;
    private static string _current = "0";

    public string CurrentNumber()
    {
        if (_expiry < DateTime.Now)
        {
            _expiry = DateTime.Now.AddSeconds(5);
            _current = Get8Digits();
        }

        return _current;
    }

【讨论】:

  • 一个请求,如果同一个程序在多台电脑上运行,那么会有一个变化来为两台电脑生成相同的号码。所以我可以让它成为明智的用户标识。用户 ID 可以是数字或字母数字的集合。那么告诉我如何根据用户 ID 生成随机数,该随机数将在接下来的 5 秒内保持活动状态?
  • @Thomas:如果给定的用户 ID 值相同,两台机器必须在相同的时间间隔内生成相同的随机数?这大大改变了问题。只要两台机器上的时间同步,RB 的解决方案就可以更新来处理这个问题,但是现在有一个更重要的问题要问你。你真正想要达到什么目标?
【解决方案2】:
private static Stopwatch age; // init me
private static int lastRandom = 0;
public static int GetTimestamp()
{
  if (age.Elapsed.TotalSeconds>5 ||lastRandom==0){
     lastRandom = Guid.NewGuid().GetHash(); // stronger random than Random
     age.Reset();
  }
  return lastRandom % 100000; // limit the digits to 6, assuming leading 0s
}

【讨论】:

  • 我建议不要使用Guid().GetHash() 作为随机生成器,因为这不是它的本意。使用RandomSystem.Security.Cryptography.RandomNumberGenerator 以获得更强的随机性。
  • Random 甚至不是一个像样的随机数生成器,如果你建议 for 它。 GUID使用Cryto
  • 这一行给出概率 lastRandom = Guid.NewGuid().GetHash();所以我使用 RandomNumberGenerator.Create() 但问题是 lastRandom 变量的数据类型是什么?请修改你的代码。谢谢
  • 你可以使用 RandomNumberGenerator.Create() 代替 Guid.NewGuid().GetHash();并相应地修改你的代码。
  • @Thomas 您可以使用您的Get8Digits 并存储字符串。我建议不要每次都制作新的 RNG
【解决方案3】:

您可以使用时间模 5 秒(实际上是时间 - 时间 % 5s)为伪随机生成器播种。它会起作用,但它不是获得好的不可预测数字的最佳方法。

用代码编辑:

Random random = new Random(DateTime.Now.Ticks - (DateTime.Now.Ticks % 50000000));

Edit2 包含更多代码:

int random5 = random.Next(100000, 999999)

【讨论】:

  • “每次随机”是什么意思?在 5 秒的时间范围内,种子将相同,因此随机数也将相同。但我同意你的观点,只使用第一个生成的 PRNG 编号效率不高。
  • 这不会更难猜测只返回日期时间刻度 - 随机将是可预测的,每个人都可以计算给定时间,不符合“任何人都可以猜到”部分
  • 我没有返回日期时间刻度,您应该使用随机对象生成一个随机数,正如 RB 在他自己的答案中显示的那样。
  • 我可以看到它没有返回刻度 - 它首先将它们打乱,但是以可预测的方式 - 除了刻度之外没有返回任何新信息
  • 在你的情况下如何获得实际数字?你能写出完整的代码来返回数字吗?谢谢
【解决方案4】:

我理解您的问题是您想要生成一个随机数生成器,该生成器将每 5 秒生成一个不同的随机数。

public int GetRandomValue() 
{
    // Seed the RNG with an integer that changes every 5 seconds.
    Random rnd = new Random((int)(DateTime.Now.Ticks / ticksIn5Seconds));
    // Generate a 6 digit random number.
    return rnd.Next(100000, 999999); 
}

【讨论】:

  • 这每次都是随机的,不会保持5秒
  • @StenPetrov 不,不是。我已经编辑了答案,以明确我们没有重用 Random 对象,以防不明显。
  • 这不是一个“随机”数字,它返回时间戳的可预测哈希
  • @Thomas,这不是一个好的解决方案。结果可能是“随机的”,但并非不可预测。任何人都可以预测任何给定时间的数字。丹的解决方案更好。随机计算一次并以 5 秒为间隔重复使用。
  • @Dialectus 是的,这就是仅使用带有预测种子的第一个生成数字的问题。这就是使这个解决方案优雅但不是很有效的原因。
猜你喜欢
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 2018-12-21
  • 2014-11-24
相关资源
最近更新 更多