问题 我们可以解码Guid以找出它产生的位置和时间吗?


本文 解释了如何生成Guids。

我的问题是,有什么方法可以找出我的网站中哪台机器生成了这个Guid以及何时?


2521
2017-08-23 10:07


起源

是的 - 您需要执行此操作的所有信息都在该文章和链接的互联网草案中。这假定您的GUID是使用该算法生成的,如果它是使用不同的算法生成的,则需要查找该算法的规范/详细信息。您可以使用Variant字段(在链接的备忘录中描述)来确定使用的布局变体。 - Justin


答案:


尼尔芬威克是对的。但是我们可以利用这种结构来获得优势。

版本4 (。净)

版本4 UUID使用仅依赖于随机数的方案。该算法设置版本号以及两个保留位。使用随机或伪随机数据源设置所有其他位。版本4 UUID的格式为xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,其中x是任何十六进制数字,y是8,9,A或B之一。 f47ac10b-58cc-4372-a567-0e02b2c3d479。

使用版本字段

我们可以自由地改变字节8的第一个半字节;因此,如果您的机器少于17台,您可以通过更改在每台机器上创建的GUID来识别它们。

static Guid NewSystemGuid(int machine)
{
    if (machine < 0 | machine > 0xF)
        throw new ArgumentOutOfRangeException("machine");
    var g = Guid.NewGuid();
    var arr = g.ToByteArray();
    arr[7] = (byte)((machine << 4) | (arr[7] & 0xF));
    return new Guid(arr);
}

static int ExtractMachine(Guid guid)
{
    var arr = guid.ToByteArray();
    return (arr[7] >> 4) & 0xF;
}

使用版本字段和'y'

我不确定更改Y是否会改变GUID的唯一性,因此您的里程可能会有所不同。如果少于17台机器坚持使用第一种解决方案。

static Guid NewSystemGuid(int machine)
{
    if (machine < 0 | machine > 0xFF)
        throw new ArgumentOutOfRangeException("machine");

    var m1 = machine & 0xF;
    var m2 = (machine >> 4) & 0xF;

    var g = Guid.NewGuid();
    var arr = g.ToByteArray();
    arr[7] = (byte)((m1 << 4) | (arr[7] & 0xF));
    arr[8] = (byte)((m2 << 4) | (arr[8] & 0xF));
    return new Guid(arr);
}

static int ExtractMachine(Guid guid)
{
    var arr = guid.ToByteArray();
    return 
        ((arr[7] >> 4) & 0xF) |
        (((arr[8] >> 4) & 0xF) << 4);
}

使用版本和'y'(Redux)

您仍然可以通过将机器数量限制为63来保留'y'中的值(使用最后2位代表'y'的4个可能值):

static Guid NewSystemGuid(int machine)
{
    if (machine < 0 | machine > 0x3F)
        throw new ArgumentOutOfRangeException("machine");

    var m1 = machine & 0xF;
    var m2 = (machine >> 4) & 0xF;

    var g = Guid.NewGuid();
    var arr = g.ToByteArray();
    arr[7] = (byte)((m1 << 4) | (arr[7] & 0xF));

    var y = (arr[8] >> 4) & 0xF;
    switch (y)
    {
        case 0x8:
            arr[8] = (byte)((m2 << 4) | (arr[8] & 0xF));
            break;
        case 0x9:
            arr[8] = (byte)(((m2 | 0x8) << 4) | (arr[8] & 0xF));
            break;
        case 0xA:
            arr[8] = (byte)(((m2 | 0x4) << 4) | (arr[8] & 0xF));
            break;
        case 0xB:
            arr[8] = (byte)(((m2 | 0xC) << 4) | (arr[8] & 0xF));
            break;
        default:
            throw new Exception();
    }
    return new Guid(arr);
}

static int ExtractMachine(Guid guid)
{
    var arr = guid.ToByteArray();
    return 
        ((arr[7] >> 4) & 0xF) |
        (((arr[8] >> 4) & 0x3) << 4);
}

使用版本1 GUID

您还可以使用版本1 GUID,因为它仍然可以生成它们:

class SequentialGuid
{
    [DllImport("rpcrt4.dll", SetLastError = true)]
    static extern int UuidCreateSequential(out Guid guid); 

    public static Guid NewGuid()
    {
        Guid guid;
        UuidCreateSequential(out guid);
        return guid;
    }

    public static byte[] ExtractMacAddress(Guid guid)
    {
        var arr = guid.ToByteArray();
        // Require version 1.
        if (((arr[7] >> 4) & 0xF) != 1)
            throw new ArgumentOutOfRangeException("guid", "GUID is required to be a sequential (version 1) GUID.");

        var macLong = BitConverter.ToInt64(arr, arr.Length - 8);
        macLong = IPAddress.NetworkToHostOrder(macLong);
        arr = BitConverter.GetBytes(macLong);
        Array.Resize(ref arr, 6);

        return arr;
    }
}

13
2017-08-23 11:06



这是一个很大的努力:) - Faisal
@Faisal如果评论解决了你的问题,记得接受它:)。 - Jonathan Dickinson
我确实记得它;我只是在等待其他一些答案。接受:) - Faisal