18-значный уникальный идентификатор - надежность кода - PullRequest
5 голосов
/ 26 июня 2010

Я хочу, чтобы число было уникальным навсегда, я придумал следующий код, он генерирует число и добавляет к его концу контрольную цифру, я хотел бы знать, насколько надежен этот код?

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 с помощью телефонной клавиатуры.

Ответы [ 9 ]

6 голосов
/ 26 июня 2010

Вы не можете использовать GUID, но вы можете создать свой собственный формат уникального номера, похожий на GUID, который основан на MAC-адресе аппарата (пробел) и текущем времени и дате (время). Это гарантированно будет уникальным, если все машины имеют синхронизированные часы.

Для получения дополнительной информации см. здесь

5 голосов
/ 26 июня 2010

Почему бы вам просто не использовать Guid?

4 голосов
/ 26 июня 2010

Есть несколько проблем с этим методом:

  • Вы просто подсчитываете количество миллисекунд с 1 января 1970 года. Вы можете получить это значение от ts.TotalSeconds с округлением до 0,0000001. Все ваши преобразования и миллисекундные вычисления не нужны.

  • 10 лет - это примерно 3 × 10¹¹ миллисекунд. Вы сохраняете 17 значащих цифр, поэтому в течение следующих 10 лет первые 5 цифр никогда не изменятся и не могут использоваться для различения чисел. Они бесполезны.

  • Вы генерируете числа для миллисекунд между 1970 и сейчас? В противном случае они также не могут использоваться для различения чисел и являются бесполезными.

  • Это полностью зависит от того, какая машина возвращает дату. Любой, кто имеет доступ к этой машине, может генерировать любые «уникальные» числа, которые они хотят. Это проблема?

  • Каждый, кто видит одно из этих чисел, может сказать, когда он был сгенерирован. Это проблема?

  • Любой может предсказать, какое число будет сгенерировано, когда. Это проблема?

  • 10 15 миллисекунд составляет около 30000 лет. После этого ваш алгоритм будет повторять числа. Похоже, давно, но вы указали «навсегда» и 30000 лет не «навсегда». Вы действительно имеете в виду «навсегда»?

3 голосов
/ 26 июня 2010

Если я правильно понимаю вашу реализацию, она использует только текущую дату / время в качестве основы.Это означает, что если вы создадите два идентификатора одновременно, они не будут уникальными.

1 голос
/ 26 июня 2010

Использование системного времени - хорошее начало, но оно дает вам коллизии, если вам нужно сгенерировать два UID одновременно.Это не помогает, что вы используете формат "fffffff": разрешение часов Windows составляет всего 15-16 мс, так что только один или два из этих "f" приносят пользу.

ТакжеВаш подход говорит вам точно, когда был создан идентификатор.В зависимости от ваших потребностей, это может быть желательной функцией или угрозой безопасности.

Ваши идентификаторы потребуются для включения другой информации вместо времени или в дополнение к нему.Возможны следующие варианты:

  • Случайное число
  • Циклический счетчик
  • Хеш имени программы (если вам нужны эти идентификаторы в нескольких программах)
  • MAC-адрес или другой идентификатор для машины (если идентификаторы должны быть уникальными на нескольких компьютерах)

Если вы хотите обеспечить уникальность , сохраните вашИдентификаторы в базе данных, чтобы вы могли проверять наличие дубликатов.

1 голос
/ 26 июня 2010

Вы не говорите, для чего используются цифры. Есть ли у них какая-то ценность, связанная с ними? Будет ли проблемой, если пользователи смогут выяснить схему и угадать действительные номера билетов?

Если для этих чисел важно угадать, эта схема рушится; что-то, что выводит данные, которые выглядят действительно случайными, было бы лучше. Вы можете взять монотонно увеличивающийся серийный номер и зашифровать его с помощью блочного шифра (с размером блока 64 бита); это дает вам 64-битный вывод или около 20 десятичных цифр, которые вы могли бы взять (скажем) последние 18 из. (Если важна обратимость, т. Е. Учитывая номер билета, который вы хотите, чтобы иметь возможность восстановить серийный номер, вам необходимо быть здесь более осторожным.)

Вам нужна чугунная 100% гарантия того, что номера билетов никогда не будут прежними? Если это так, вам нужно сохранить их в базе данных и пометить их при использовании. Если вы сделаете это, может быть разумно просто использовать хороший генератор случайных чисел и каждый раз проверять наличие дупликов.

1 голос
/ 26 июня 2010

Поскольку вы упомянули (в комментариях), что идентификаторы хранятся в БД, вы можете сгенерировать идентификаторы, используя метод, который вы упомянули, или случайным образом и проверить наличие в БД.существует, сгенерируйте новый, иначе все готово.

Одна вещь, я бы позаботился о том, чтобы проверка транзакции на наличие идентификатора и фактическое сохранение записи в БД проводилась в транзакциив противном случае вы рискуете сделать еще один запрос на создание этой записи между проверкой идентификатора и созданием строки.

Также просто проверяете, почему бы не было автоматически увеличенного числа, сгенерированного базой данныхсама работа?БД гарантирует ее уникальность (для этой таблицы в любом случае)

0 голосов
/ 26 июня 2010

В любом случае нет такой вещи, как случайность. Вот предложение.

  1. Создайте свой собственный "случайный" 18-значный номер
  2. Перед отправкой пользователю, проверьте его на существующие в БД
  3. Если уже есть в БД, промыть и повторить.
0 голосов
/ 26 июня 2010

Как говорит «Эндрю Хэйр», вы можете использовать Guid .О вашем коде ответ "НЕТ"!потому что, если DateTime компьютера клиента был неправильным или результат изменения может быть пара или больше!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...