kipway@outlook.com
2017.1.26
GUID(Globally Unique Identifier),全局唯一标识符,是一种由算法生成,无需认证机构管理的二进制长度为128位的数字标识符,微软在Windows系统的注册表中用来标识COM对象的类厂和接口,是UUID的具体实现。在软件编程中,常将GUID当作索引使用。
在windows系统中,有平台sdk函数CoCreateGuid可以直接调用,在Linux系统中无相应的系统调用,但有第三方库可用。本文给出一个windows/linux平台均可用的C++实现的GUID计算方法。
guid本质上是一个16字节的数据,按照如下结构体组织:
struct t_guid
{
unsigned int v1;
unsigned short v2;
unsigned short v3;
unsigned char v4[8];
};
其实这16字节如何组织没有关系,主要目的要保证计算出来的这16字节尽量随机离散。MD5校验值,也叫MD5摘要值正好是128位共16字节长度,不同源数据的MD5摘要 值重复的概率完全满足GUID重复概率的要求。而且MD5算法的离散型非常好,源数据只要有一位的不同生成的MD5摘要差别很大,因此只要保证源数据能不同就可使用MD5算法计算出满足要求的GUID。
这里源数据采用以下4部分组成,当然你还可以增加一些字段,比如你的有效邮箱地址和你的手机号,进一步保证生成的guid是全球唯一的:
可以按照如下结构体定义:
#ifdef _WIN32
struct t_guidinfo
{
FILETIME ts; // 时标,8字节
unsigned int pid; // 进程pid
unsigned int seqno; // 进程内递增序列号
unsigned char mac[8]; // 网卡mac地址
} _uinfo;
#else
struct t_guidinfo
{
timespec ts; // 时标,16字节
unsigned int pid; // 进程pid
unsigned int seqno; // 进程内递增序列号
unsigned char mac[8]; // 网卡mac地址
} _uinfo;
#endif
接下来就是获取网卡MAC地址,获取时间,计算MD5摘要等,均可从查资料得到,下面给出完整的代码以便理解:
/*!
\file c_guid.h
\author kipway@outlook.com
*/
#ifndef C_GUID_H
#define C_GUID_H
#include <time.h>
#include "c_netmac.h"
#include "c_md5.h"
#ifdef _WIN32
#include <process.h>
#endif
namespace ec
{
struct t_guid
{
unsigned int v1;
unsigned short v2;
unsigned short v3;
unsigned char v4[8];
};
class cGuid
{
protected:
#ifdef _WIN32
struct t_guidinfo
{
FILETIME ts; // 时标,8字节
unsigned int pid; // 进程pid
unsigned int seqno; // 进程内递增序列号
unsigned char mac[8]; // 网卡mac地址
} _uinfo;
#else
struct t_guidinfo
{
timespec ts; // 时标,16字节
unsigned int pid; // 进程pid
unsigned int seqno; // 进程内递增序列号
unsigned char mac[8]; // 网卡mac地址
} _uinfo;
#endif
public:
cGuid() {
memset(&_uinfo, 0, sizeof(_uinfo));
if (!ec::getnetmac(_uinfo.mac, 1))
{
size_t i;
for (i = 0; i < sizeof(_uinfo.mac); i++)
_uinfo.mac[i] = (unsigned char)(0xC1 + i);
}
_uinfo.pid = getpid();
_uinfo.seqno = 1;
}
void uuid(t_guid *pguid)
{
#ifdef _WIN32
GetSystemTimeAsFileTime(&_uinfo.ts);
#else
clock_gettime(CLOCK_REALTIME, &_uinfo.ts);
#endif
_uinfo.seqno++;
ec::encode_md5(&_uinfo, sizeof(_uinfo), (unsigned char*)pguid);
}
};
}
#endif
具体测试和使用例子:
/*!
\file tstguid.cpp
*/
#include "ec/c_system.h"
#include "ec/c_guid.h"
ec::cGuid g_clsguid;//全局对象保证进程内guid唯一。
void printfguid(ec::t_guid * p)
{
printf("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", p->v1, p->v2, p->v3, p->v4[0], p->v4[1],
p->v4[2], p->v4[3], p->v4[4], p->v4[5], p->v4[6], p->v4[7]);
}
int main()
{
ec::t_guid guids[16];
int i;
for (i = 0; i < 16; i++)
{
g_clsguid.uuid(&guids[i]);
printfguid(&guids[i]);
}
return 0;
}
这是在我的机器上例子输出的结果:
{8D030A83-0AE2-3990-3EA5-33CC66ED794E}
{1B3A78FE-CC00-BE9D-2D0A-407865D9D656}
{7ED49EAA-5290-5BE6-A47B-5206F6098E5C}
{847C56AF-7640-322A-0415-E2BDB4682393}
{98EE22BC-94B2-1406-C7E4-31CEAE09F446}
{0010977D-B657-A926-3AB6-4C6F44A91760}
{3051A369-AC9B-49FD-44EE-94AFEEC9E173}
{2E565A1B-56DF-FD16-EF9C-B77B8B004B76}
{89F55B89-F7EE-FF69-4297-F46663A42A31}
{5A5CC12E-0D6A-D7F5-7688-5FF9E4836502}
{D3BC7DFA-83F6-34B0-7B64-8093365B7D6E}
{2C2727C9-83D1-E081-8B0B-A59808FEFF7D}
{C49AE6DB-72E5-E7A9-4A73-0CBEB91E15F3}
{69E931AD-0B2D-2CBA-3520-8C20EA0E8FFC}
{4F57BB42-D484-EAC0-90CD-B26CB60B7FF7}
{FC302D9D-5472-33D8-AE3E-4A5C96BA5A54}