1. 程式人生 > >網遊伺服器中的GUID(唯一標識碼)實現

網遊伺服器中的GUID(唯一標識碼)實現

本文中的演算法採用twitter的snowflake演算法,具體請搜尋介紹,原來是用Scala寫的,因我專案需要,改寫成C++語言,主要用於高效的生成唯一的ID, 核心演算法就是毫秒級時間(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等等資料,方便記錄和追蹤。