【问题标题】:18 Digit Unique ID - Code reliability18 位唯一 ID - 代码可靠性
【发布时间】:2010-06-26 14:19:50
【问题描述】:

我想要一个永远唯一的数字,我想出了以下代码, 它生成一个数字并在其末尾添加一个校验位,我想知道这个代码有多可靠?

public void GenerateUniqueNumber(out string ValidUniqueNumber) {
        string GeneratedUniqueNumber = "";

        // Default implementation of UNIX time of the current UTC time
        TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        string FormatedDateTime = Convert.ToInt64(ts.TotalSeconds).ToString();
        string ssUniqueId = DateTime.UtcNow.ToString("fffffff");
        //Add Padding to UniqueId
        string FormatedUniqueId = ssUniqueId.PadLeft(7, '0'); 

        if (FormatedDateTime.Length == 10 && FormatedUniqueId.Length == 7)
        {
            // Calculate checksum number using Luhn's algorithm.
            int sum = 0;
            bool odd = true;
            string InputData = FormatedDateTime + FormatedUniqueId;
            int CheckSumNumber;

            for (int i = InputData.Length - 1; i >= 0; i--)
            {
                if (odd == true)
                {
                    int tSum = Convert.ToInt32(InputData[i].ToString()) * 2;
                    if (tSum >= 10)
                    {
                        string tData = tSum.ToString();
                        tSum = Convert.ToInt32(tData[0].ToString()) + Convert.ToInt32(tData[1].ToString());
                    }
                    sum += tSum;
                }
                else
                    sum += Convert.ToInt32(InputData[i].ToString());
                odd = !odd;
            }
            //CheckSumNumber = (((sum / 10) + 1) * 10) - sum;
            CheckSumNumber = (((sum + 9) / 10) * 10) - sum;

            // Compute Full length 18 digit UniqueNumber
            GeneratedUniqueNumber = FormatedDateTime + FormatedUniqueId + Convert.ToString(CheckSumNumber);
        }
        else
        {
            // Error
            GeneratedUniqueNumber = Convert.ToString(-1);
        }

        ValidUniqueNumber = GeneratedUniqueNumber;        
    }

编辑:澄清 不能使用 GUID,需要通过电话键盘将号码输入 IVR 系统。

【问题讨论】:

  • 您能否向我们提供有关您使用它的上下文的更多详细信息?例如,为什么你只想要数字(Guid 无论如何)?
  • IVR 系统中使用的号码是什么?某种身份?确认号码?越详细越好!
  • 需要输入IVR系统,所以不能使用GUID。另外要求号码最多只能是18位。
  • @Matthew,是的,IVR 会提示用户使用他的手机或电话键盘将号码输入系统,然后它会验证号码。
  • 在哪种情况下独一无二?数字是在一个中心位置生成的(如果是,一个简单的整数,每个数字递增,会起作用),还是必须在多个独立设备上动态生成?每个设备是否都有一个唯一的标识符,可以用作 ID 的一部分?

标签: c# asp.net uniqueidentifier


【解决方案1】:

您不能使用 GUID,但您可以创建类似于 GUID 的唯一编号的 own 格式,它基于机器的 MAC 地址(空格)和当前时间和日期(时间)。如果机器都具有同步时钟,则保证是唯一的。

更多信息请见here

【讨论】:

    【解决方案2】:

    你为什么不直接使用Guid

    【讨论】:

    • Guid 只是一个 128 位的数字。 “字母”只是该数字的十六进制表示 - 这样更容易阅读。
    • 但是如果他的限制是十进制格式的18位,那么GUID就太大了,对吧?
    • @Aaronaught:没必要嘲笑他。如果他已经什么都知道了,他就不需要问了。请参阅常见问题解答中的“友善”部分:stackoverflow.com/faq
    • @Matthew:如果您开始从 GUID 中切分,则它不再是全局唯一的。这是一个非常糟糕的主意。
    • @Matthew,GUID 不是随机的。它们是全球唯一的,因为它们包含一个 MAC 地址(唯一的、全球管理的)和一个准确的高分辨率时间戳。因此,它们是时空坐标,如果没有 MAC 地址冲突,它们是不可能发生冲突的。请参阅blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx 了解说明
    【解决方案3】:

    这个方法有几个问题:

    • 您基本上只是在计算从 1970 年 1 月 1 日开始的毫秒数。您可以从 ts.TotalSeconds 得到这个值,四舍五入到 0.0000001。你所有的转换和毫秒计算都是不必要的。

    • 10 年大约是 3×10¹¹ 毫秒。您保留 17 位有效数字,因此在接下来的 10 年中,前 5 位数字永远不会改变,也不能用于区分数字。它们没用。

    • 您是否正在生成 1970 年到现在之间的毫秒数?如果不是,它们也不能用于区分数字,没有用处。

    • 这完全取决于返回日期的机器。任何有权访问这台机器的人都可以生成他们想要的任何“唯一”数字。这是问题吗?

    • 任何看到这些数字之一的人都可以知道它是何时生成的。这是个问题吗?

    • 任何人都可以预测何时会生成什么数字。这是个问题吗?

    • 1015 毫秒大约是 30000 年。之后,您的算法将重复数字。似乎很长一段时间,但是您指定了“永远”,而 30000 年不是“永远”。你真的是指“永远”吗?

    【讨论】:

    • 我刚刚注意到您要求TotalSeconds 中的位数等于10。这将在32 年后中断,因此您的前7 位数是无用的。如果你必须截断到 10 位,你应该修改 10000000000。
    • 这完全取决于返回日期的机器。任何有权访问这台机器的人都可以生成他们想要的任何“唯一”数字。这是问题吗?
    • @Khou,输入错误!实际上是 300 年:wolframalpha.com/input/?i=10000000000+seconds 不过还是应该使用 mod。
    【解决方案4】:

    如果我正确理解您的实现,它只使用当前日期/时间作为基础。这意味着如果您同时创建两个 ID,它们将不会是唯一的。

    【讨论】:

      【解决方案5】:

      由于您提到(在 cmets 中)ID 存储在数据库中,您可以使用您提到的方法或随机生成 ID 并检查数据库中是否存在。

      如果已经存在,则生成一个新的,否则就完成了。

      但有一件事,我会确保在事务中检查 ID 是否存在以及将记录实际保存到数据库中,否则您将冒着让另一个请求在两个请求之间创建该记录的风险检查 ID 和行的创建。

      也只是检查一下,为什么数据库本身生成的自动递增数字不起作用?数据库将保证它的唯一性(无论如何对于该表)

      【讨论】:

        【解决方案6】:

        你没有说这些数字是用来做什么的。它们是否具有某种与它们相关的价值?如果用户能弄清楚方案并猜出有效的票号,会不会有问题?

        如果这些数字很难猜到很重要,那么这个方案就失败了;输出看起来非常随机的数据会更好。您可能会采用单调递增的序列号并使用块密码(具有 64 位块大小)对其进行加密;这为您提供了 64 位输出或大约 20 位十进制数字,您可以取(比如说)最后 18 位。 (如果可逆性很重要,即给定一个票号,您希望能够恢复序列号,您需要在这里更加小心。)

        您是否需要 100% 的铸铁保证票号永远不会相同?如果是这样,您需要将它们保存在数据库中并在使用时将它们标记出来。如果你这样做了,那么只使用一个好的随机数生成器并每次检查是否有欺骗性可能是合理的。

        【讨论】:

          【解决方案7】:

          使用系统时间是一个好的开始,但如果您需要同时生成两个 UID,它会给您带来冲突。使用“fffffff”格式并没有帮助:Windows 时钟分辨率只有 15-16 毫秒,因此这些“f”中只有一两个有好处。

          此外,您的方法可以准确地告诉您 ID 的生成时间。根据您的需要,这可能是一个理想的功能,也可能存在安全风险。

          除了时间之外,您还需要在 ID 中包含其他信息。一些可能的选择是:

          • 一个随机数
          • 循环计数器
          • 程序名称的哈希(如果您在多个程序中需要这些 ID)
          • 机器的 MAC 地址或其他标识符(如果 ID 需要在多台计算机上是唯一的)

          如果您想确保唯一性,请将您的 ID 存储在数据库中,以便检查重复项。

          【讨论】:

            【解决方案8】:

            正如“Andrew Hare”所说,您可以使用Guid。 关于您的代码,答案是“否”! 因为如果客户计算机的 DateTime 错误或更改结果可能是一对或更多!

            【讨论】:

              【解决方案9】:

              反正没有随机的东西。这是一个建议。

              1. 创建您自己的“随机”18 位数字
              2. 在将其发送给用户之前,将其与 DB 中现有的进行检查
              3. 如果已经在 DB 中,请冲洗并重复。

              【讨论】:

              • 天哪,在没有 cmets 的情况下投了反对票,接下来呢? ;-) 此处不应使用时间戳,并且假定您在编码时考虑到了并发性。数据库检查保证没有重复;我错过了什么吗?如何生成数字取决于您的情况的安全需求。您的问题表明您希望该数字“永远唯一”,这解决了它:-)
              • 随机和独特不是一回事。尝试使用 随机 数字来生成 唯一 标识符是一个非常糟糕的主意。即使假设您检查以前使用过的数字的数据库(并且问题没有表明这样的数据库存在,甚至可能在他的环境中),也有一个理论上的非停止算法的风险和主要性能瓶颈的非常现实的风险。在回答有关唯一标识符的问题时,人们需要停止使用“随机”一词。如果你有一个数据库,counter 会更有意义。
              • Khou 在其原始问题的 cmets 部分指出了一个 DB。
              猜你喜欢
              • 2010-10-15
              • 1970-01-01
              • 2015-01-10
              • 2011-02-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-05-04
              • 2012-04-05
              相关资源
              最近更新 更多