Calendar

July 2010
M T W T F S S
« Jun   Aug »
 1234
567891011
12131415161718
19202122232425
262728293031  

UUID を生成するいろいろな方法


はじめに

UUID (Universally Unique Identifier) とは (1)誰でも自由に生成できる (2)世界中でただ一つのユニークな番号 のことです。

UUIDはユニークな値であることを前提に使えるため、様々な用途で使用されています。例えば…

  • WindowsのActiveXのコンポーネントID (古!)
  • LinuxのHDD管理
    最近のLinuxディストリビューションをお使いなら、 /etc/fstab で確認出来ます。
  • SOAP等の通信メッセージの識別用

等々です。

UUIDの詳細は Wikipedia などにお任せするとして、ここでは UUIDを生成する色々な方法についてまとめてみます。

コマンドを使って生成

まずは、Linuxのターミナルや、Windowsのコマンドプロンプトから、コマンドを使って生成する方法についてです。

Unix系(Linuxなど)

uuidgenコマンドを使用します。

(書式)

uuidgen [ -r | -t ]  

(オプション)

  • -r (デフォルト)
    乱数を使って UUID を生成します。生成される UUID は Version.4仕様です。
  • -t
    現在時刻とMACアドレスを元に生成します。生成される UUID は Version.1仕様です。

(例)

$ uuidgen
a7c4eab7-1540-47bd-9302-7fda5df5c54e

15文字目(赤い箇所)が UUID のバージョンを表してます。('4' は Version.4 を表す)

(参考)
Manpage of UUIDGEN (www.linux.or.jp)

Windows

MicrosoftのGUID生成ツール(GUIDGEN)を使う

GUIDGen.EXE は Visual Studio に付属するツールですが、Visual Studioを持っていなくても、Microsoftからダウンロードして使用出来ます。

GUIDEGEN のダウンロード (Microsoft)

(実行画面)
guidgen

(使い方)

  1. GuidGen.exe を起動します。
  2. Guid Format を選択します。
  3. [Copy]ボタンを押して、テキストをクリップボードにコピーします。
  4. テキストエディタ等に貼り付けます。
cygwin の uuidgen を使う

cygwin にも uuidgen コマンドが含まれています。 Unix版と引数が異なり生成アルゴリズムの選択は出来ませんが、Version.4のUUIDを生成するので問題ないと思います。

GUI操作が不要なので、こちらの方が素早く作れます。

プログラムから生成

次に色々なプログラム言語から生成してみます。C/C++, Java, Python, PHP, Perl, Ruby を取り上げます。

Windows/Visual C++

UuidCreate() で UUID を生成し、UuidToString() で文字列化します。 以下がその例です。

(サンプル)

#include <rpc.h>

unsigned char *p;
UUID uuid;

::UuidCreate(&uuid );                  // UUID生成
::UuidToString(&uuid, &p );            // UUIDを文字列にする

char str[38];
strncpy(str, (char*)p, sizeof(str));   // 自分で用意したバッファにコピー

::RpcStringFree(&p );                  // 解放 (これ以降、pの指すアドレスにアクセスしていけない)

また、VC++のプロジェクト設定で、リンカーの入力に Rpcrt4.lib を追加します。

上のサンプルコードを使用したVisual C++プロジェクト全体を、下のリンクからダウンロード出来ます。

VC++サンプルプロジェクトのダウンロード (Visual C++ 2010 Express Edition形式です)

(MSDN の APIリファレンス)
使用しているAPI関数の詳細はMSDNで確認出来ます。

C/C++ と libuuid

libuuidライブラリで用意されている uuid_generate() で UUID を生成、uuid_unparse() で文字列化します。 以下がその例です。

(サンプル – uuid_test.cpp)

#include <uuid/uuid.h>
#include <iostream>

int main(int argc, char** argv)
{
  uuid_t u;
  char buf[37];

  uuid_generate(u);
  uuid_unparse(u, buf);

  std::cout << buf << std::endl;
  return 0;
}

ビルドする時は、libuuid のリンク指定 (-luuid) が必要です。

(ビルド・実行例)

$ g++ uuid_test.cpp -luuid
$ ./a.out 
0c91356c-c16a-44c7-9709-448993b6ce07

(参考)
- Manpage of UUID_GENERATE (www.linux.or.jp)

C++ と Boost

Boost の ver.1.42 で UUID関連機能が追加され、UUID を生成出来るようになりました。 (2010/7/28時点の最新版は ver.1.43.0 です)

(サンプル - uuid_boost_test.cpp)

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <sstream>

int main (int , char * const [])
{
  boost::uuids::basic_random_generator gen;
  boost::uuids::uuid u = gen();

  std::stringstream ss;
  ss << u;
  std::cout << ss.str() << std::endl;
  return 0;
}

(ビルド・実行例)

$ g++ uuid_boost_test.cpp
$ ./a.out 
8699e324-3701-4c31-9a29-abdfe99ea93d

(参考)
- boost/uuid/random_generator.hpp

Java

java.util.UUIDクラスを使います。

(サンプル - UUIDTest.java)

import java.util.UUID;

public class UUIDTest {

  public static void main(String[] args) {
    UUID uuid = UUID.randomUUID();
    System.out.println(uuid.toString());
  }
}

(ビルド・実行例)

$ javac UUIDTest.java 
$ java UUIDTest
d47e2bd7-9538-41ae-85ac-2d52367a1a3c

Python

uuidモジュールを使って生成します。

(サンプル - uuid_test.py)

#!/usr/bin/env python

import uuid

print uuid.uuid4()

(実行例)

$ chmod u+x ./uuid_test.py 
$ ./uuid_test.py 
699e824b-82e2-48dd-afc5-6e41c6833a2a

(参考)
- Python ライブラリリファレンス - uuidモジュールの利用方法

PHP

PHP拡張モジュール(PECL) の一つである uuid 拡張モジュール を使ってみます。

(サンプル - uuid_test.php)

<?php
  echo uuid_create(UUID_TYPE_RANDOM)."\n";
?>

(実行例)

$ php uuid_test.php
95c889f7-8644-4848-9114-7eecba3f3354

(PECL uuid 拡張モジュールの導入)

Ubuntu 10.04 では、先に php5-dev, php-pear パッケージをインストールしておきます。

$ sudo apt-get install php5-dev
$ sudo apt-get install php-pear

その後、PECLモジュールをインストールします。

$ sudo pecl install uuid
downloading uuid-1.0.2.tgz ...
Starting to download uuid-1.0.2.tgz (6,217 bytes)
.....done: 6,217 bytes
3 source files, building
running: phpize
Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626
uuid installation directory? [autodetect] : [Enterを入力]
building in /var/tmp/pear-build-root/uuid-1.0.2

=== 中略 ===

Build process completed successfully
Installing '/usr/lib/php5/20090626/uuid.so'
install ok: channel://pecl.php.net/uuid-1.0.2
configuration option "php_ini" is not set to php.ini location
You should add "extension=uuid.so" to php.ini
$

Perl

CPAN の Data::UUIDモジュールを使ってみます。

(サンプル - uuid_test.pl)

use Data::UUID;

print Data::UUID->new->create_str(), "\n";

(実行例)

$ perl uuid_test.pl
0CF7FD18-8F4D-11DF-91FA-A306AD4192EE

(CPAN - Data::UUIDモジュールの導入)
Data::UUID が入ってないときは、次のようにインストールして下さい。

$ sudo perl -MCPAN -e 'install Data::UUID'

Ruby

最後は Ruby で締めます。
uuidtools を使ってみます。

(サンプル - uuid_test.rb)

require 'uuidtools'

p UUIDTools::UUID.random_create.to_s

(実行例)

$ ruby uuid_test.rb 
"6921cf45-059a-4e5d-bd96-fb2679da27ea"

補足

当然、ここで挙げた以外の多くの言語でも UUID発生器が実装されています。例えば、Wikipediaでは、Lisp, Haskell, JavaScript, Delphi, Lua, ... 等々の言語が挙げてあります。

最後に

色々な言語のサンプルを揃えたので、なんとなく Wikipedia の Hello worldプログラムの一覧 みたいになってしまいましたが、それくらい色々な言語から利用出来ると言えます。

実装済みのライブラリを使って UUID を生成するだけなら非常に簡単です。ユニークなIDが必要になった時は UUID の使用を考えてみるのも良いと思います。

おまけ: (怪談)UUIDが重複!?

UUIDの生成には、(1)質の良い乱数発生器と、(2)アルゴリズムの選択が重要になります。

以前、組込み機器の開発案件でデータ管理IDにUUIDを使った時、ごくまれに同じUUIDを生成するという問題が起きました。

調べた結果、この機器にはバッテリーバックアップがなく、毎回同じ時刻から起動することが判明しました。しばらくするとネットワーク経由で時刻補正されて現在時刻に移るのですが、それまでは毎回同じ時刻を刻んでいます。そして時刻補正前にUUIDを生成すると、まれに以前生成したものと同じUUIDを生成していました。乱数発生の種(時刻)が同じなので、同じ結果になっていたようです。

この時は、時刻補正が終わるまでUUIDを生成しないようにして問題を回避しましたが、乱数の種の重要性を認識させられました。

Comments are closed.