簡體   English   中英

全球和本地唯一的10個字符ID

[英]10 character id that's globally and locally unique

我需要生成一個10個字符的唯一ID(SIP / VOIP人士需要知道它是針對P-Charging-Vector標頭中的參數icid-value的)。 每個字符應為26個ASCII字母(區分大小寫)之一,10個ASCII數字之一或連字符減號。

它必須是“全局唯一的(在生成ID的機器外部)”和足夠的“本地唯一的(在生成ID的機器內部)”,所有這些都必須打包成10個字符,!

這是我的看法。 我首先將“必須”編碼為全局唯一的本地ip地址編碼為base-63(其無符號長整數,編碼后將占用1-6個字符),然后按當前時間戳盡可能多地編碼一個time_t / long long int,它將在編碼后占用9-4個字符,具體取決於編碼后的IP地址首先占用多少空間。

我還為時間戳添加了循環計數“ i”,以保持唯一性,以防該函數每秒被調用多次。

這是否足以在全球和本地獨一無二,還是還有另一種更好的方法?

高拉夫

#include <stdio.h>
#include <string.h>
#include <sys/time.h>

//base-63 character set
static char set[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";

// b63() returns the next vacant location in char array x
int b63(long long longlong,char *x,int index){
    if(index > 9)
        return index+1;

    //printf("index=%d,longlong=%lld,longlong%63=%lld\n",index,longlong,longlong%63);
    if(longlong < 63){
        x[index] = set[longlong];
        return index+1;
    }  

    x[index] = set[longlong%63];
    return b63(longlong/63,x,index+1);
}

int main(){
    char x[11],y[11] = {0}; /* '\0' is taken care of here */

    //let's generate 10 million ids
    for(int i=0; i<10000000; i++){

        /*  add i to timestamp to take care of sub-second function calls,
            3770168404(is a sample ip address in n/w byte order) =                84.52.184.224 */
        b63((long long)time(NULL)+i,x,b63((long long)3770168404,x,0));

        // reverse the char array to get proper base-63 output
        for(int j=0,k=9; j<10; j++,k--)
            y[j] = x[k];

        printf("%s\n",y);
    }

    return 0;
}

它必須是“全局唯一的(在生成ID的機器外部)”和足夠的“本地唯一的(在生成ID的機器內部)”,所有這些都必須打包成10個字符,!

您可以控制所有生成ID的軟件嗎? 您是否在分發ID? 如果不...

我對SIP一無所知,但是您對規范有一定的誤解(否則規范一定是錯誤的)。 如果另一位開發人員嘗試使用與您編寫的算法不同的算法來構建ID,則您的ID將會發生沖突,這意味着他們將知道該系統在全局范圍內不再唯一。

我將返回SIP文檔,看看是否有一個附錄,其中包含用於生成這些ID的算法。 或者,也許是比我能回答生成這些ID的SIP算法更聰明的SO用戶。

我會認真看一下RFC 4122,它描述了128位GUID的生成。 有幾種不同的生成算法,其中一些可能適合(基於MAC地址的一種出現)。 這個數字空間比2 ^ 128 = 3.4 * 10 ^ 38的數字空間大,而63 ^ 10 = 9.8 * 10 ^ 17的數字空間更大,因此您可能必須在唯一性方面做出一些妥協。 考慮諸如ID生成頻率的因素。

但是,在RFC中,他們考慮了一些實際問題,例如通過預分配ID塊來有效生成大量唯一值的能力。

您不能只擁有一個分布式ID表嗎?

具有NAT的LAN上的計算機通常具有較小范圍的IP,並且並非所有的32位值都有效(請考慮多播等)。 機器也可以獲取相同的時間戳,尤其是在粒度較大(例如秒)的情況下; 請記住,年份通常是相同的,因此較低的位會給您最大的“獨特性”。

您可能需要采用各種值,使用加密哈希對它們進行哈希處理,然后將其轉換為允許使用的字符,將其截斷為10個字符。

但是您要處理的值少於60位; 您需要仔細考慮碰撞的影響。 您可能以錯誤的方式來解決問題...

好吧,如果我拋棄一個事實,那就是我認為這不是一個好主意,而是專注於解決您的問題,那么我將要做的是:

您的ID范圍為10 ^ 63,大約相當於60位。 您希望它既“全局”又“本地”唯一。 讓我們生成前N位是全局唯一的,其余的是本地唯一的。 兩者的串聯將具有您要查找的屬性。

首先,全球唯一性:IP無效,尤其是本地IP,它們的熵很小。 我會使用MAC地址,因為它們是全球唯一的。 它們覆蓋的范圍為256 ^ 6,因此使用了6 * 8 = 48位。

現在,對於本地唯一的:為什么不使用進程ID? 我假設唯一性是每個過程,如果不是,則必須考慮其他因素。 在Linux上,進程ID為32位。 如果我們想要nitpick,則最高2個字節可能只具有很少的熵,就像大多數計算機上的熵一樣。 因此,如果您知道自己在做什么,就將其丟棄。

因此,現在您將看到一個問題,因為它將使用多達70位來生成一個不錯的(但不是防彈的)全局和本地唯一ID(無論如何使用我的技術)。 並且由於我也建議輸入一個隨機數(至少8位長)以防萬一,因此絕對不合適。 因此,如果您是我,我會將〜78個生成的位散列到SHA1(例如),並將生成的散列的前60位轉換為您的ID格式。 為此,請注意您有63個字符范圍可供選擇,因此幾乎是6位的整個范圍。 因此,將哈希分成6位,並使用前10位從63個字符范圍中選擇ID的10個字符。 顯然,6位的范圍是64個可能的值(您只需要63),因此如果您有一個6位等於63,則將其下限為62或取模63並選擇0。這會稍微影響分布,但這還不錯。

因此,在那里,您應該可以獲得不錯的全局和本地偽唯一ID。

最后幾點:根據生日悖論 ,生成約1.42億個ID后,發生碰撞的機率約為1%,生成30億個ID后,發生沖突的機率約為99%。 因此,如果您獲得了巨大的商業成功,並且生成了數百萬個ID,則可以獲取更大的ID。

最后,我認為我為您的問題提供了“比糟糕的解決方案更好的解決方案”,但我忍不住認為您以錯誤的方式來解決此問題,並且可能就像其他人提到的那樣,誤讀了規范。 因此,如果沒有其他方法可以更“防彈”(集中式ID提供程序,更長的ID ...),請使用此方法。

編輯:我重新閱讀了您的問題,並且您說您每秒可能多次調用此函數。 我以為這是作為某種應用程序ID,在您的應用程序啟動時生成一次,直到它退出后才更改。 既然不是這種情況,則一定要添加一個隨機數,並且如果生成大量ID,則至少應使用32位數字。 並閱讀並重新閱讀我上面鏈接的《生日悖論》。 然后將數字生成器設置為一個高熵值,例如當前時間戳的usec值。 甚至甚至可以從/ dev / urandom獲取隨機值。 老實說,我的努力是60位可能還不夠...

嗯,使用系統時鍾可能是一個弱點……如果有人將時鍾調回原位該怎么辦? 您可能會再次重新生成相同的ID。 但是,如果要使用時鍾,則可以調用gettimeofday()而不是time()。 至少這樣一來,您將獲得比一秒鍾更好的分辨率。

@Doug T.不,我不能控制所有生成ID的軟件。 我同意,如果沒有標准化算法,可能會發生沖突,因此我在相應的郵件列表中提出了此問題。

@Florian從您那里得到提示。 我決定將/ dev / urandom PRNG用作32位隨機數,作為id的空間唯一組成部分。 我假設每台機器都會有自己的噪聲特征,並且可以假設它在某個時刻在空間上具有全局安全性。 我之前使用的時間唯一組件保持不變。

生成這些唯一的id來整理從不同網絡功能收集的所有計費信息,這些功能在呼叫處理期間獨立生成特定呼叫的計費信息。

這是下面的更新代碼:

高拉夫

 #include <stdio.h>
 #include <string.h>
 #include <time.h>

 //base-63 character set
 static char set[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";

 // b63() returns the next vacant location in char array x
 int b63(long long longlong, char *x, int index){
     if(index > 9)
         return index+1;

     if(longlong < 63){
         x[index] = set[longlong];
         return index+1;
     }  

     x[index] = set[longlong%63];
     return b63(longlong/63, x, index+1);
 }

 int main(){
     unsigned int number;
     char x[11], y[11] = {0};

     FILE *urandom = fopen("/dev/urandom", "r");
     if(!urandom)
         return -1;

     //let's generate a 1 billion ids
     for(int i=0; i<1000000000; i++){

         fread(&number, 1, sizeof(number), urandom);

         // add i to timestamp to take care of sub-second function calls, 
         b63((long long)time(NULL)+i, x, b63((long long)number, x, 0));

         // reverse the char array to get proper base-63 output
         for(int j=0, k=9; j<10; j++, k--)
             y[j] = x[k];

         printf("%s\n", y);
     }

     if(urandom)
     fclose(urandom);

     return 0;
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM