MySQL如何存储IP地址, Java和PHP IP地址与int或者long类型互转

2019-02-16 07:48:09   MySQL

对数据库了解的同学都知道数字类型其实是要比字符串类型的column在处理上速度快很多的,所以为了存储和查询速度考虑,我们通常把IP地址转为数字来存储,通常用int存储,但是要注意要使用unsigned ,不然128以上的就无法存储了。

原理

那我们究竟如何存储IP地址呢?

  • 我们知道IP地址(ipv4)分为四段,每一段的范围是0-255,而这个范围恰好可以用8bit的二进制来表示,因为2的8次方为256,从0到255正好为256个数字。
  • 所以,实际上我们可以用类似xxxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx 的形式来表示一个ipv4的地址,其中x 为0或1。
  • 然后,我们把中间的点去掉,就是一个32bit的二进制数字了,恰好是一个int类型(数据库中占32bit)所能表示的范围。
  • 因此,我们只需要将IP每一段都用二进制表示,再拼到一起,就可以表示一个IP地址了。

如何拼装

  • 10.1.8.12 为例,四段分别是101812,用8bit的二进制表示分别为00001010000000010000100000001100,其中不足8位的数字用0在左边补齐。
  • 最后我们要的结果其实是00001010000000010000100000001100,也就是按照顺序,拼接起来,转为十进制位167839756(我口算的,你们信不;-))。
  • 我们依次从左到右这四段,分别左移24位、16位、8位、0位,Java中位用逻辑左移运算符<< ,然后我们可以得到00001010000000000000000000000000000000010000000000000000 , 0000110000000000, 00001100
  • 最后我们将这几段二进制数做或操作,Java中逻辑或运算符为| (有一个为1则此位为1)于是我们就可以得到00001010000000010000100000001100 , 十进制就是167839756.

如何还原

  • 明白了如何拼装的之后,我们还原就很容易了
  • 我们把这个长长的数字右移,分别把00001010000000010000100000001100 右移24位、16位、8位、0位,然后得到00001010000010100000000100001010000000010000100000001010000000010000100000001100
  • 然后,我们用11111111 也就是 0xFF 来跟上述的四段数字以此做与操作,java中运算符位& (同1为1,有一个为0则此位为0), 我们就可以得到00001010000000010000100000001100,十进制依次为:101812,最后中间加点,就还原了。
  • 这个与操作实际上就是起到了截断的作用,只取8位,因为0xFF 只有8位,其左边可以用任意多的0填充,例如0xFF 跟 例子IP中的第三段做与操作:000000000000000011111111 & 000010100000000100001000,根据与运算的规则,高于8位的都是跟0与,所以得到的也全是0,真正有效的低8位。
  • 事实上,开头的10 ,我们完全可以不用与操作,因为右移24位后,就剩下8位,就是我们要的。

代码实现

Java

package com.vien.ip;

/**
 * @author Vien
 * @date 2017/11/17
 */

public class IPUtils {
    /**
     * convert ip to long
     *
     * @param ip the string of ip address
     * @return long of ip
     */
    public static long ip2long(String ip) {
        System.out.println(ip);
        String[] slice = ip.split("\\.");
        return (Long.valueOf(slice[0]) << 24) | (Long.valueOf(slice[1]) << 16) | (Long.valueOf(slice[2]) << 8) | Long.valueOf(slice[3]);
    }

    /**
     * convert long to ip
     *
     * @param ip long
     * @return string of ip
     */
    public static String long2ip(long ip) {
        StringBuilder ipStr = new StringBuilder();
        ipStr.append((ip >>> 24)).append(".");
        ipStr.append((ip >>> 16) & 0xFF).append(".");
        ipStr.append((ip >>> 8) & 0xFF).append(".");
        ipStr.append(ip & 0xFF);
        return ipStr.toString();
    }

    public static void main(String[] args) {
        System.out.println(ip2long("10.1.8.12"));
        System.out.println(long2ip(167839756));
    }
}

PHP

其实PHP提供了相关函数
ip2long() 将 IP转为long
long2ip() 将 long还原为IP

MySQL

MySQL也提供相关函数,可以用于查询,例如:

mysql> select inet_aton('10.1.8.12');
+------------------------+
| inet_aton('10.1.8.12') |
+------------------------+
|              167839756 |
+------------------------+
1 row in set (0.01 sec)
mysql> select inet_ntoa(167839756);
+----------------------+
| inet_ntoa(167839756) |
+----------------------+
| 10.1.8.12            |
+----------------------+
1 row in set (0.00 sec)

更多:vien.我爱你

vien.tech版权所有,允许转载,但转载请注明出处和原文链接: https://viencoding.com/article/34
欢迎小伙伴们在下方评论区留言 ~ O(∩_∩)O
文章对我有帮助, 点此请博主吃包辣条 ~ O(∩_∩)O

猜你喜欢


评论

There are no comments yet.
未登录

登录后即可发表评论

登录或注册