GCTT | 干货来了,该学学IP地址转换了,数字与字符串之间的转换

IP 地址库中 IP 地址的保存格式一般有两种,一种是点分十进制形式(192.168.1.1),另一种是数字形式(3232235777),应用中,经常需要在这两种格式之间做转换。

针对这一个问题我在 exnet 扩展包里面实现可两者的转换的快捷方法:
func IP2Long(ip net.IP) (uint, error)

 IP2Long 把 net.IP 转为数值func Long2IP(i uint) (net.IP, error)

 Long2IP 把数值转为 net.IPfunc IPString2Long(ip string) (uint, error)
 IPString2Long 把 ip 字符串转为数值func Long2IPString(i uint) (string, error)

 Long2IPString 把数值转为 ip 字符串
使用示例:


go 
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) // 会得到一个16字节的byte,主要为了兼容ipv6 
  n, _ = exnet.IP2Long(Ip1) 

  Ip2, _ := exnet.Long2IP(n) 

  fmt.Println(n, reflect.DeepEqual(Ip1[12:], Ip2)) 
} 
那么是如何将点分十进制的IP地址转为数字?
IPv4 地址有4个字节,样式如下: 
MSB————–LSB
b4 b3 b2 b1
每个字节表示的范围:
  • 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
转换方法:222<<24 | 173<<16 | 108<<8 | 86 = 3735907414
再例如,1.0.1.1
转换方法:1<<24 | 0<<16 | 1<<8 | 1 = 16777473

exnet 中实现如下:

go 
// IPString2Long 把ip字符串转为数值 
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])
把数值转换为字符串的逻辑翻转过来即可, exnet 中实现如下:

go 
// Long2IPString 把数值转为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 
} 

9