IP地址轉(zhuǎn)換:數(shù)字與字符串之間的轉(zhuǎn)換
IP 地址庫中 IP 地址的保存格式一般有兩種,一種是點(diǎn)分十進(jìn)制形式(192.168.1.1),另一種是數(shù)字形式(3232235777),應(yīng)用中,經(jīng)常需要在這兩種格式之間做轉(zhuǎn)換。
針對(duì)這一個(gè)問題我在 exnet 擴(kuò)展包里面實(shí)現(xiàn)可兩者的轉(zhuǎn)換的快捷方法:
- func IP2Long(ip net.IP) (uint, error) IP2Long 把 net.IP 轉(zhuǎn)為數(shù)值
- func Long2IP(i uint) (net.IP, error) Long2IP 把數(shù)值轉(zhuǎn)為 net.IP
- func IPString2Long(ip string) (uint, error) IPString2Long 把 ip 字符串轉(zhuǎn)為數(shù)值
- func Long2IPString(i uint) (string, error) Long2IPString 把數(shù)值轉(zhuǎn)為 ip 字符串
使用示例:
- package main
- import (
- "fmt"
- "net"
- "reflect"
- "github.com/thinkeridea/go-extend/exnet"
- )
- func main() {
- ip := "192.168.1.1"
- n, _ := exnet.IPString2Long(ip)
- s, _ := exnet.Long2IPString(n)
- fmt.Println(n, s == ip)
- Ip1 := net.ParseIP(ip) // 會(huì)得到一個(gè)16字節(jié)的byte,主要為了兼容ipv6
- n, _ = exnet.IP2Long(Ip1)
- Ip2, _ := exnet.Long2IP(n)
- fmt.Println(n, reflect.DeepEqual(Ip1[12:], Ip2))
- }
那么是如何將點(diǎn)分十進(jìn)制的IP地址轉(zhuǎn)為數(shù)字?
IPv4 地址有4個(gè)字節(jié),樣式如下:
- MSB————–LSB
- b4 b3 b2 b1
每個(gè)字節(jié)表示的范圍:
- byte4: 4294967296(1<<32)
- byte3: 16777216(1<<24)
- byte2: 65536(1<<16)
- byte1: 256(1<<8)
通用公式:b4<<24 | b3<<16 | b2<<16 | b1
例如,222.173.108.86
轉(zhuǎn)換方法:222<<24 | 173<<16 | 108<<8 | 86 = 3735907414
再例如,1.0.1.1
轉(zhuǎn)換方法:1<<24 | 0<<16 | 1<<8 | 1 = 16777473
exnet 中實(shí)現(xiàn)如下:
- // IPString2Long 把ip字符串轉(zhuǎn)為數(shù)值
- func IPString2Long(ip string) (uint, error) {
- b := net.ParseIP(ip).To4()
- if b == nil {
- return 0, errors.New("invalid ipv4 format")
- }
- return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
- }
把數(shù)值轉(zhuǎn)換為字符串的邏輯翻轉(zhuǎn)過來即可, exnet 中實(shí)現(xiàn)如下:
- // Long2IPString 把數(shù)值轉(zhuǎn)為ip字符串
- func Long2IPString(i uint) (string, error) {
- if i > math.MaxUint32 {
- return "", errors.New("beyond the scope of ipv4")
- }
- ip := make(net.IP, net.IPv4len)
- ip[0] = byte(i >> 24)
- ip[1] = byte(i >> 16)
- ip[2] = byte(i >> 8)
- ip[3] = byte(i)
- return ip.String(), nil
- }