指引网

当前位置: 主页 > 编程开发 > C >

基于snowflake算法的网游服务器唯一标识码GUID生成方法

来源:网络 作者:佚名 点击: 时间:2017-07-19 23:07
[摘要]  snowflake算法是twitter出来的,原来是用Scala写的,现在我改成C++,nowflake用于生成高效的生成唯一ID,现在我把ID用于网游服务器唯一标识码。

在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12位。

网上也有好多PHP写的插件模块,核心用了网络通讯将生成的ID发送给PHP使用,没深入研究PHP的模块写法。

废话不多说了,还是直接上代码好了。

uuid.h

#ifndef __UTIL_UUID_H__
#define __UTIL_UUID_H__

#include <stdint.h>

namespace utils
{
// twitter snowflake算法
// 64       63--------------22---------12---------0
// 符号位   |     41位时间   |10位机器码|12位自增码|
extern uint64_t get_time();

class unique_id_t
{
public:
    unique_id_t();
    ~unique_id_t();

    void set_epoch(uint64_t epoch);
    void set_machine(int32_t machine);
    int64_t generate();

private:
    uint64_t epoch_;
    uint64_t time_;
    int32_t machine_;
    int32_t sequence_;
};

}

#endif // !__UTIL_UUID_H__

uuid.cpp

#include "uuid.h"
#if defined(__GUNC__)
#include <sys/time.h>
#include <unistd.h>
#define EPOCHFILETIME 11644473600000000ULL
#else
#include <windows.h>
#include <time.h>
#define EPOCHFILETIME 11644473600000000Ui64
#endif

namespace utils
{
    uint64_t get_time()
    {
#ifdef __GUNC__
        struct timeval tv;
        gettimeofday(&tv, NULL);
        uint64 time = tv.tv_usec;
        time /= 1000;
        time += (tv.tv_sec * 1000);
        return time;
#else
        FILETIME filetime;
        uint64_t time = 0;
        GetSystemTimeAsFileTime(&filetime);

        time |= filetime.dwHighDateTime;
        time <<= 32;
        time |= filetime.dwLowDateTime;

        time /= 10;
        time -= EPOCHFILETIME;
        return time / 1000;
#endif
    }

    unique_id_t::unique_id_t()
    {
        epoch_ = 0;
        time_ = 0;
        machine_ = 0;
        sequence_ = 0;
    }

    unique_id_t::~unique_id_t()
    {

    }

    void unique_id_t::set_epoch(uint64_t epoch)
    {
        epoch_ = epoch;
    }

    void unique_id_t::set_machine(int32_t machine)
    {
        machine_ = machine;
    }

    int64_t unique_id_t::generate()
    {
        int64_t value = 0;
        uint64_t time = get_time() - epoch_;

        // 保留后41位时间
        value = time << 22;

        // 中间10位是机器ID
        value |= (machine_ & 0x3FF) << 12;

        // 最后12位是sequenceID
        value |= sequence_++ & 0xFFF;
        if (sequence_ == 0x1000)
        {
            sequence_ = 0;
        }

        return value;
    }
}

#ifdef __TEST__
#include <iostream>
void test()
{
    utils::unique_id_t* u_id_ptr = new utils::unique_id_t();
    u_id_ptr->set_epoch(uint64_t(1367505795100));
    u_id_ptr->set_machine(int32_t(100));
    for (int i = 0; i < 1024; ++i)
    {
        std::cout << u_id_ptr->generate() << std::endl;;
    }
}
#endif

这样的唯一ID就可以用来表示你系统中使用的例如物品唯一ID,坐骑唯一ID等等数据,方便记录和追踪。

------分隔线----------------------------