code

Go 언어로 UUID를 생성하는 방법이 있습니까?

codestyles 2020. 8. 29. 11:04
반응형

Go 언어로 UUID를 생성하는 방법이 있습니까?


다음과 같은 코드가 있습니다.

u := make([]byte, 16)
_, err := rand.Read(u)
if err != nil {
    return
}

u[8] = (u[8] | 0x80) & 0xBF // what does this do?
u[6] = (u[6] | 0x40) & 0x4F // what does this do?

return hex.EncodeToString(u)

길이가 32 인 문자열을 반환하지만 유효한 UUID라고 생각하지 않습니다. 그것은 실제 UUID 인 경우, 이유는 UUID, 그리고 코드가 수정의 값의 목적은 무엇인가 u[8]하고 u[6].

UUID를 생성하는 더 좋은 방법이 있습니까?


u[8] = (u[8] | 0x80) & 0xBF // what's the purpose ?
u[6] = (u[6] | 0x40) & 0x4F // what's the purpose ?

이 행은 바이트 6 및 8의 값을 특정 범위로 고정합니다. UUID에 대해 모두 유효한 값이 아닌 rand.Read범위의 임의의 바이트를 반환합니다 0-255. 내가 말할 수있는 한, 이것은 슬라이스의 모든 값에 대해 수행되어야합니다.

Linux를 사용하는 경우 /usr/bin/uuidgen.

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    out, err := exec.Command("uuidgen").Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", out)
}

결과 :

$ go run uuid.go 
dc9076e9-2fda-4019-bd2c-900a8284b9c4

go-uuid 라이브러리를 사용하여 UUID를 생성 할 수 있습니다 . 다음과 함께 설치할 수 있습니다.

go get github.com/nu7hatch/gouuid

다음을 사용하여 임의 (버전 4) UUID를 생성 할 수 있습니다.

import "github.com/nu7hatch/gouuid"

...

u, err := uuid.NewV4()

반환 된 UUID유형은 16 바이트 배열이므로 이진 값을 쉽게 검색 할 수 있습니다. 또한 String()메서드 를 통해 표준 16 진 문자열 표현을 제공합니다 .

또한 코드는 유효한 버전 4 UUID를 생성하는 것처럼 보입니다. 마지막에 수행하는 비트 조작은 UUID의 버전 및 변형 필드를 설정하여 버전 4로 올바르게 식별합니다 . 이는 임의의 UUID를 다른 알고리즘 (예 : MAC 주소 및 시간을 기반으로 한 버전 1 UUID)을 통해 생성 된 것과 구별하기 위해 수행됩니다.


go-uuid라이브러리는 RFC4122에 호환되지 않습니다. 변형 비트가 올바르게 설정되지 않았습니다. 커뮤니티 구성원이이 문제를 수정하려고 여러 번 시도했지만 수정에 대한 풀 요청이 수락되지 않았습니다.

You can generate UUIDs using the Go uuid library I rewrote based on the go-uuid library. There are several fixes and improvements. This can be installed with:

go get github.com/twinj/uuid

You can generate random (version 4) UUIDs with:

import "github.com/twinj/uuid"

u := uuid.NewV4()

The returned UUID type is an interface and the underlying type is an array.

The library also generates v1 UUIDs and correctly generates v3 and 5 UUIDs. There are several new methods to help with printing and formatting and also new general methods to create UUIDs based off of existing data.


"crypto/rand" is cross platform pkg for random bytes generattion

package main

import (
    "crypto/rand"
    "fmt"
)

func pseudo_uuid() (uuid string) {

    b := make([]byte, 16)
    _, err := rand.Read(b)
    if err != nil {
        fmt.Println("Error: ", err)
        return
    }

    uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

    return
}

You should use google/uuid https://github.com/google/uuid

package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    id, err := uuid.NewUUID()
    if err !=nil {
        // handle error
    }
    fmt.Printf(id.String())
}

This package is RFC4122 and DCE 1.1 compliant


gofrs/uuid is the replacement for satori/go.uuid, which is the most starred UUID package for Go. It supports UUID versions 1-5 and is RFC 4122 and DCE 1.1 compliant.

import "github.com/gofrs/uuid"

// Create a Version 4 UUID, panicking on error
u := uuid.Must(uuid.NewV4())

There is an official implementation by Google: https://github.com/google/uuid

Generating a version 4 UUID works like this:

package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    id := uuid.New()
    fmt.Println(id.String())
}

Try it here: https://play.golang.org/p/6YPi1djUMj9


From Russ Cox's post:

There's no official library. Ignoring error checking, this seems like it would work fine:

f, _ := os.Open("/dev/urandom")
b := make([]byte, 16)
f.Read(b)
f.Close()
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

Note: In the original, pre Go 1 version the first line was:

f, _ := os.Open("/dev/urandom", os.O_RDONLY, 0)

Here it compiles and executes, only /dev/urandom returns all zeros in the playground. Should work fine locally.

In the same thread there are some other methods/references/packages found.


As part of the uuid spec, if you generate a uuid from random it must contain a "4" as the 13th character and a "8", "9", "a", or "b" in the 17th (source).

// this makes sure that the 13th character is "4"
u[6] = (u[6] | 0x40) & 0x4F
// this makes sure that the 17th is "8", "9", "a", or "b"
u[8] = (u[8] | 0x80) & 0xBF 

The gorand package has a UUID method that returns a Version 4 (randomly generated) UUID in its canonical string representation ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") and it's RFC 4122 compliant.

It also uses the crypto/rand package to ensure the most cryptographically secure generation of UUIDs across all platforms supported by Go.

import "github.com/leonelquinteros/gorand"

func main() {
    uuid, err := gorand.UUID()
    if err != nil {
        panic(err.Error())
    }

    println(uuid)
} 

On Linux, you can read from /proc/sys/kernel/random/uuid:

package main

import "io/ioutil"
import "fmt"

func main() {
    u, _ := ioutil.ReadFile("/proc/sys/kernel/random/uuid")
    fmt.Println(string(u))
}

No external dependencies!

$ go run uuid.go 
3ee995e3-0c96-4e30-ac1e-f7f04fd03e44

For Windows, I did recently this:

// +build windows

package main

import (
    "syscall"
    "unsafe"
)

var (
    modrpcrt4 = syscall.NewLazyDLL("rpcrt4.dll")
    procUuidCreate = modrpcrt4.NewProc("UuidCreate")
)

const (
    RPC_S_OK = 0
)

func NewUuid() ([]byte, error) {
    var uuid [16]byte
    rc, _, e := syscall.Syscall(procUuidCreate.Addr(), 1,
             uintptr(unsafe.Pointer(&uuid[0])), 0, 0)
    if int(rc) != RPC_S_OK {
        if e != 0 {
            return nil, error(e)
        } else {
            return nil, syscall.EINVAL
        }
    }
    return uuid[:], nil
}

This library is our standard for uuid generation and parsing:

https://github.com/pborman/uuid

참고URL : https://stackoverflow.com/questions/15130321/is-there-a-method-to-generate-a-uuid-with-go-language

반응형