我一直在执行网络协议,并且我要求数据包具有唯一的标识符。到目前为止,我只是生成随机的32位整数,并假设从天文学角度来看,在程序/连接的生命周期内不会发生冲突是不太可能的。这是生产代码中通常被认为可以接受的做法,还是应该设计一种更复杂的系统来防止冲突?
我一直在执行网络协议,并且我要求数据包具有唯一的标识符。到目前为止,我只是生成随机的32位整数,并假设从天文学角度来看,在程序/连接的生命周期内不会发生冲突是不太可能的。这是生产代码中通常被认为可以接受的做法,还是应该设计一种更复杂的系统来防止冲突?
Answers:
当心生日悖论。
假设您正在从一组大小为N(在您的情况下为N = 2 ^ 32)中生成一个随机值序列(均匀地,独立地)。
然后,生日悖论的经验法则规定,一旦生成了大约sqrt(N)值,则至少有50%的机会发生了冲突,即,在碰撞中至少有两个相同的值。生成的序列。
对于N = 2 ^ 32,sqrt(N)= 2 ^ 16 =65536。因此,在生成大约65k标识符之后,它们中的两个很可能发生碰撞!如果您每秒生成一个标识符,则将在不到一天的时间内发生;不用说,许多网络协议的运行速度都比后者快。
如果随机数具有足够的比特,则依靠随机数是唯一的被广泛认为是可以接受的。在某些加密协议中,重复随机数会破坏整个安全性。只要所使用的随机数生成器中没有严重的漏洞,就没有问题。
用于生成UUID的一种算法将有效地生成由122个随机位组成的ID,并假定它是唯一的。其他两种算法依赖于被截断为122位的唯一的哈希值,这具有大致相同的冲突风险。
因此,有一些标准依赖于122位足以使随机ID唯一,但是32位绝对不够。如果使用32位ID,则在碰撞风险达到50%之前只需要大约21个ID,因为使用21个ID时,将有近23对对,每对可能是碰撞。
甚至122位也比我在任何新设计中建议的要少。如果遵循一些标准化对您很重要,请使用UUID。否则,请使用大于122位的内容。
具有160位输出的SHA1哈希函数不再被认为是安全的,部分原因是160位不足以保证输出的唯一性。现代哈希函数的输出范围是224位到512位。随机生成的ID应以相同的大小为目标,以确保唯一性和良好的安全裕度。
sqrt(2^122)
= 2.3万亿五次方的UUID
urandom
并不会比使用UUID库更多。我只是在Python中实现了两者进行比较,每种方法恰好是源代码的25个字符。
我称这种不好的做法。随机数生成只是不创建唯一数,而只是创建随机数。随机分布可能包含一些重复项。通过添加时间元素,可以使这种情况的发生不太可能。如果从系统时钟获取当前时间(以毫秒为单位)。像这样:
parseToInt(toString(System.currentTimeMillis()) + toString(Random.makeInt()))
将会走很长一段路。显然,要真正保证唯一性,您需要使用UUID / GUID。但是生成它们可能会很昂贵,以上可能就足够了,因为重叠的唯一可能性是,如果随机生成在同一毫秒内具有重复项。
currentTimeMillis
。
System.currentTimeMillis
,一个包含Random.makeInt()
,则发生碰撞的可能性将大大降低。但是,这不是本示例中的代码执行的操作。给定任何先前时间和随机值以及任何当前时间,发生碰撞的概率与两个随机数首先发生碰撞的概率相同。
可以假设随机数是唯一的,但是您必须小心。
假设您的随机数是均匀分布的,发生碰撞的可能性大约为(n 2/2)/ k,其中n是您生成的随机数的数量,k是“随机”数可以取的可能值的数量。
您不必将数字放在天文数字上不太可能,因此可以将其设为2 30中的 1 (大约10亿)。进一步说,您生成了2个30个数据包(如果每个数据包代表大约一千字节的数据,那么这意味着大约一兆字节的总数据,虽然很大,但并非难以想象)。我们发现我们需要一个至少2 89个可能值的随机数。
首先,您的随机数必须足够大。一个32位随机数最多可以有2 32个可能的值。对于繁忙的服务器而言,它远远不够高。
其次,您的随机数生成器需要具有足够大的内部状态。如果您的随机数生成器仅具有32位内部状态,那么无论您生成的值有多大,您最多仍只能获得2 32个可能的值。
第三,如果您需要随机数在连接中唯一,而不是仅在连接内唯一,则您的随机数生成器必须是种子良好的。如果您的程序经常重新启动,则尤其如此。
通常,编程语言中的“常规”随机数生成器不适合此类用途。通常由密码库提供的随机数生成器。
很多人已经给出了高质量的答案,但是我想补充一些要点:首先,@ nomadictype关于生日悖论的观点非常出色。
另一点:随机性并不像人们通常认为的那样直接生成和定义。(实际上,实际上有针对随机性的统计检验)。
话虽如此,重要的是要意识到“ 赌徒的谬论”,这是一种统计谬论,人们认为独立事件在某种程度上会相互影响。随机事件通常在统计上彼此独立-即,如果您随机生成一个“ 10”,则它至少不会改变您将来生成更多“ 10”的可能性。(也许有人可以提出该规则的例外,但我希望几乎所有随机数生成器都是这种情况)。
因此,我的回答是,如果您可以假设足够长的随机数序列是唯一的,那么它们就不是真正的随机数,因为这将是一个清晰的统计模式。此外,这也意味着每个新数字都不是独立事件,因为例如生成10,则表示将来生成10的概率为0%(不可能发生),再加上这意味着您增加获得10以外的数字的几率(即,生成的数字越多,剩余数字中每个数字出现的可能性就越高)。
我还要考虑的另一件事是:据我所知,单场比赛赢得强力球的机会约为1.75亿分之一。但是,某人获胜的几率要高得多。您对某人 “获胜”(即成为重复)的几率比对任何特定数字“获胜” /成为重复的几率更感兴趣。
不管使用多少位-您都不能保证两个“随机”数将不同。相反,我建议您使用诸如计算机的IP地址或其他网络地址之类的东西和一个序列号,最好是HONKIN'BIG序列号-128位(显然是无符号的)听起来像是一个好的开始,但是256更好。