# Go IP如何储存进去MYSQL --- ```javascript= 要了解IP是如何储存的进去MYSQL数据库的,需要从这个几个方面下手: 1. IP与数值类型的转换 2. IP地址跟MYSQL的数据存储之间的关系 3. MYSQL数据如何处理IP类型 ``` ## 1. IP与数值类型的转换 :::success ```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) // 以ip字符串形式读取数据 // 192*256*256*256+168*256*256+1*256+1 = 3232235777 fmt.Println(n, s == ip) // 3232235777 true Ip1 := net.ParseIP(ip) // 会得到一个16字节的byte,主要为了兼容ipv6 n, _ = exnet.IP2Long(Ip1) // 以数值类型存储进去数据库 Ip2, _ := exnet.Long2IP(n) // 以ip字符串形式读取数据 fmt.Println(Ip1) // 192.168.1.1 fmt.Println(n) // 3232235777 fmt.Println(Ip1) // 192.168.1.1 fmt.Println(n, reflect.DeepEqual(Ip1[12:], Ip2)) // 3232235777 true } // ParseIP,IPString2Long,Long2IPString,IP2Long,Long2IP 源码函数 // ParseIP 把ip字符串转为IP类型 type IP []byte func ParseIP(s string) IP { for i := 0; i < len(s); i++ { switch s[i] { case '.': // ipv4地址 return parseIPv4(s) case ':': // ipv6地址 return parseIPv6(s) } } return nil } // 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])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil } // 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 } // IP2Long 把net.IP转为数值 func IP2Long(ip net.IP) (uint, error) { b := 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 } // Long2IP 把数值转为net.IP func Long2IP(i uint) (net.IP, error) { if i > math.MaxUint32 { return nil, 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, nil } ``` ::: ## 2. IP地址跟MYSQL的数据存储之间的关系 ```javascript= ipv4大家都知道是从0.0.0.0到255.255.255.255; 然而使用IP2Long函数转换后并不是我们想象中的0到4294967295, 而是0.0.0.0-127.255.255.255,转换后为0到2147483647; 128.0.0.0-255.255.255.255转换后为-2147483647到-1; IP地址转换成int类型正好是int的有符号取整范围,为什么呢? MySQL中int类型占4个字节,每个字节占8位 // 0-255 0-127, -127--1 总大小为(2^8-1)*(2^8-1)*(2^8-1)*(2^8-1)=255*255*255*255,是不是和IP地址的范围很类似; ``` ## 3. IP地址跟MYSQL的数据存储之间的关系 - 简要说明 ```javascript= 在Mysql中并没有提供针对IP地址存储的数据格式 在开发中我们可以选择使用char、varchar、int来存储 根据mysql字段类型选择的规则: 1. 字段类型定义使用最合适(最小)、最简单的数据类型,优先选择使用int类型来存储 2. int在逻辑运算上也要比char、varchar更快 ``` - int类型存储IP地址 ```javascript= 在Mysql中提供了两个函数,用来把IP地址与数字类型的相互转化 这种算法(inet_aton())其实借用了国际上对各国IP地址的区分中使用的ip number。 A.B.C.D 的ip number是: A * 256^3 + B * 256^2 + C * 256 + D ``` ```javascript= inet_aton():把IP地址转化为数字 ``` ```sql= mysql> select inet_aton('192.168.1.1'); +------------------------------+ | inet_aton('192.168.1.1') | +------------------------------+ | 3232235777| +------------------------------+ 1 row in set (0.00 sec) ``` ```javascript= inet_ntoa():把数字转化成IP地址 ``` ```sql= mysql> select inet_ntoa(4294967295); +-----------------------+ | inet_ntoa(3232235777) | +-----------------------+ | 192.168.1.1 | +-----------------------+ 1 row in set (0.00 sec) ``` ```javascript= 当前很多应用都适用字符串char(15)来存储IP地址(占用16个字节); 利用inet_aton()和inet_ntoa()函数,来存储IP地址; 适用unsigned int 就可以满足需求,不需要使用bigint,只需要4个字节; 也节省存储空间,同时效率也高很多。 ``` ```javascript= IPV4地址由4个组数字组成,每组数字之间以.分隔,每组数字的取值范围是0-255。 [0-99,100-199,200-249,250-255] IPV4必须满足以下四条规则: 1、任何一个1位或2位数字,即0-99; 正则\d{1,2} 2、任何一个以1开头的3位数字,即100-199; 正则1\d{2} 3、任何一个以2开头、第2位数字是0-4之间的3位数字,即200-249; 正则2[0-4]\d 4、任何一个以25开头,第3位数字在0-5之间的3位数字,即250-255。 正则25[0-5] 组合起来,就得到一个匹配0-255数字的正则表达式了:(\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]) IPV4由四组这样的数字组成,中间由.隔开,或者说由三组数字和字符.和一组数字组成,所以匹配IPV4的正则表达式如下: (((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5])) ``` - 比较有价值的正则表达式(别人的博文) https://blog.csdn.net/dangjun625/article/details/83428354?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param ###### tags: `Golang` `mysql` `ip`