.NET 和 Linux 之间的 GUID/UUID 兼容性问题

GUID/UUID compatibility issue between .NET and Linux

本文关键字:UUID 兼容性 问题 GUID Linux 之间 NET      更新时间:2023-10-16

在我的 c++ 程序中,我使用 debian Linux 的 uuid 包生成一个 uuid 值,它返回了一个大小为 16 的无符号 char 数组,它的类型为 uuid_t。然后我将其转换为字符串并将其打印到控制台。

然后我获取相同的字节数组,并通过网络将其发送到Windows机器。Windows 计算机使用 .net 的 GUID 类型,并使用相同的字节数组创建一个 GUID 对象。然后,我使用 GUID 的 ToString 方法再次将其打印到控制台。令人惊讶的是,相同的字节数组在 Linux 和 .Net 下具有不同的字符串表示形式,即使它们几乎相似。

下面是一个示例:

字节数组:

101,208,176,173,236,192,

64,86,191,214,132,2,213,232,143,247

Linux:65d0b0ad-ecc0-4056-bfd6-8402d5e88ff7

。网:adb0d065-c0ec-5640-bfd6-8402d5e88ff7

您可能会注意到它们非常相似,最后一部分是相同的,第一部分使用相同的数字,只是数字的顺序不同。我按照上面解释的方式创建的每个UUID都遵循相同的模式,这让我认为存在字节顺序差异。

如何在 linux 中创建 UUID 值并使用相同的字节数组具有相同的字符串表示形式。

根据此消息和此消息,问题实际上在于对 GUID/UUID 应该是大端序还是小端序的不同理解。看起来Microsoft的实现将它们视为大端序(至少在英特尔平台上),但uuid_unparse似乎是小端序。Wiki 说 GUID(这是Microsoft的 UUID)遵循 RFC 4122 第 4.1.2 节,这似乎要求大端序排序。

因此,这是实现之间的明显不一致。作为一种解决方法,我建议以字符串格式在系统之间交换数据,这在两个系统中似乎是一致的。

不幸的是,

你不能使用相同的字节数组,并且Guid.ToString生成与 Linux 字符串匹配的字符串。

您需要决定要优先考虑哪一个:

var dotNetGuid = new Guid(new byte[] { 101, 208, 176, 173, 236, 192, 64, 86,
                                       191, 214, 132, 2, 213, 232, 143, 247 });
// option 1 - keep the existing guid's byte array intact
//            and create a new ToUnixString method to display it as-required
Console.WriteLine(dotNetGuid.ToString());      // adb0d065-c0ec-5640-bfd6-8402d5e88ff7
Console.WriteLine(dotNetGuid.ToUnixString());  // 65d0b0ad-ecc0-4056-bfd6-8402d5e88ff7
// option 2 - create a new guid by re-arranging the existing guid's byte array
//            and then use the standard ToString method
var unixGuid = dotNetGuid.ChangeByteOrder();
Console.WriteLine(dotNetGuid.ToString());  // adb0d065-c0ec-5640-bfd6-8402d5e88ff7
Console.WriteLine(unixGuid.ToString());    // 65d0b0ad-ecc0-4056-bfd6-8402d5e88ff7
// ...
public static class GuidExtensions
{
    public static string ToUnixString(this Guid guid,
        string format = "D", IFormatProvider provider = null)
    {
        return guid.ChangeByteOrder().ToString(format, provider);
    }
    public static Guid ChangeByteOrder(this Guid guid)
    {
        var s = guid.ToByteArray();
        var d = new byte[]
                    {
                        s[3], s[2], s[1], s[0], s[5], s[4], s[7], s[6],
                        s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]
                    };
        return new Guid(d);
    }
}