IP 地址字符串转不同进制的数字

版权声明:本文为博主原创文章,未经允许不得转载。 https://blog.csdn.net/MOESECSDN/article/details/84350502

不知道平时大家是怎么访问或者说是打开 Google、百度这些网站的,但我掐指一算,你会用下面几种方式。

1 收藏好网站,要打开就直接点击。

2 用域名访问,在地址栏输入域名,回车访问。

以上两种都是我们 99% 的人访问网站的方式,但难道就没有其他方式了吗?

很多猿们肯定还会说,我还可以用 IP 访问呀,你忘了?

3 用 IP 访问,在地址栏输入 IP,回车访问。

那如何获取到这个 IP 呢?其实也很简单,可以到 www.ip.cn 这个网站里输入域名来查询对应的 IP,当然也可以去其他网站中查询。也可以使用 Ping 命令 来帮助我们获取域名对应的 IP。只要我们 ping 一下域名就可以了。
在这里插入图片描述

但是你以为就只有这几种方式了吗?No,No,No!

后面的才是我要说的重点,也是我写这篇文章的目的,假如只是前面的几个点,其实没有什么好说的,99% 的人都知道。都知道的事情我何必分享呢?我要分享的当然是大家不知道的。

今天我就来泄露一下天机

4 用数字来访问,在地址栏输入协议://数字 ,回车访问。如 https://2899904127

不知大家有去试试,当我们输入协议和数字并回车后,它自动换成 IP,然后再换成域名。

更厉害的是,这个数字可以用十进制 表示,也可以用八进制 表示,还可以用十六进制 表示,我相信用其他进制也可以,但常用的进制就这些,也没那个必要,谁那么无聊会用这种方法来访问一个网站呢?要真那样,设计域名就变得毫无意义了。

但作为技术人,我们不仅要知道可以这样访问网站,还要知道其中的奥秘,也就是原理,今天就来揭秘一下。

按照协议规定,在 IPv4 中,IP 地址用二进制表示,每个 IP 地址长 32 Bit,也是 4 个字节。为了方便,人们使用「 点分十进制表示法 」表示,即每个字节的二进制数被转成十进制数
在这里插入图片描述
每个字节中间使用符号『 . 』分开,即 172.217.6.127

也就是说,我们熟知的 IP 地址字符串,本质上由二进制数按点分规则 转换而来,那既然这 IP 是一个数,那它就可以用任何一种进制来表示

先来说十进制,也就是 IP 地址字符串如何转成十进制数字?
在这里插入图片描述

我们先来看看前面 IP 地址字符串(172.217.6.127)是怎么由二进制数转换而来的
在这里插入图片描述

它是把每一个字节(8 bit)转换成十进制数,关键就在每一个字节,而每一个字节最多能存 2^8 = 256 个数。我们去掉『 . 』,前面 IP 就变成 172 217 6 127 ,也就是说它是一个 256 进制数 ,但别混淆是:127 在 256 进制中,其实就是相当于十进制的个位数,它还只是一位数而已,还没满 256,不产生进位,它是一个整体,不是多位数,其它的 172、217 在 256 进制中就相当于一位数,172 217 6 127 ,在 256 进制中就四位数是而已。
在这里插入图片描述
而我们知道,其他进制转十进制数都非常简单,套用公式就可以。

假如一个 N 进制 X 位数是:abc……yz,那就是
在这里插入图片描述
所以 IP 172 217 6 127 转换成十进制数就是

                                    172 * 256^3 + 217 * 256^2 + 6 * 256^1 + 127 * 256^0 = 2899904127

                                

在这里插入图片描述
看到这里,相信都知道为什么我们输入协议加上数字也可以访问网站了吧。

Talk Is Cheap,Show Me Code

理解了,咋们来看代码,了解一下转换过程

                                    public long ipToLong(String ipStr){
       //用 . 分割 IP 字符串,取出其中的数字
       //参数传得是正则表达式, . 有特殊意义,不能直接传,需要转义,或者用 [.] 匹配
       String[] arrayIP = ipStr.split("\\.");
       long sip1 = Integer.parseInt(arrayIP[0]);
       long sip2 = Integer.parseInt(arrayIP[1]);
       long sip3 = Integer.parseInt(arrayIP[2]);
       long sip4 = Integer.parseInt(arrayIP[3]);
       long r1 = sip1 * 256 * 256 * 256;
       long r2 = sip2 * 256 * 256;
       long r3 = sip3 * 256;
       long r4 = sip4;
       long result = r1 + r2 + r3 + r4;
       return result;
   }

                                

这样的算法通俗易懂,但不高效,空间也占得多。 咋们优化一下,看看下面的

                                    public long ipToLong(String ipStr) {
       long result = 0;
       String[] ipAddressInArray = ipStr.split("\\.");
       for (int i = 3; i >= 0; i--) {
           long ip = Long.parseLong(ipAddressInArray[3 - i]);
           // 等同 A * 256^3 + B * 256^2 + C * 256^1 + D * 256^0,运用位移更高效
           //1. 172 <<24 (左移 24 位相当于乘于 256^3 即 2^24,以下类似)
           //2. 217 <<16
           //3. 6   <<8
           //4. 127 <<0
		  // 不同数位加相 | 相当于不同数位相加( 0 | X = X)  ->1200 | 00XX = 12XX
           result |= ip <<(i * 8);
       }
       return result;
   }

                                

是不是整个人都好了。 当然还有其他的写法,就不一一列举了。

另外,我们当然也可以先把 IP 字符串转成二进制数,再转成十进制树,但这样更麻烦,还是上面的方式来得更直接。

那数字转 IP 地址字符串呢? 有前面的基础,逆向思考,下面代码应该很好理解

                                    public String longToIp(long ip) {
    return  ((ip >>24) &0xFF) + "."+
            ((ip >>16) &0xFF) + "." +
            ((ip >>8) &0xFF) + "." +
            (ip &0xFF);
}

                                

有人可能疑惑为什么要 &0xFF ?其实就是 &11111111 ,目的就是为了与出一个字节(8 bit),因为点分法是按字节(8 bit) 拆分IP的,前面说了。

图文解释可以清楚一点,先要知道,在二进制运算中,0 &X = 0,1 &X = X ,0 与任何数都得 0,1 与任何数都得任何数。

最开始是这样的,十进制数字转成二进制数字,然后拆分为四部分,如下图
在这里插入图片描述

为了取到从左边起的第一个字节,左移 24 后,只剩下 10101100
在这里插入图片描述
&0xFF&11111111 ,即 得到 10101100,转换成十进制后就是 172

说到这,可能还不是很明白,看完下面就明白了。

再看,为了取到从左边起的第二个字节,左移 16,但得到 10101100 11011001,包含了左起第一个字节。
在这里插入图片描述

但是我要取的是第二个字节 11011001,所以就再 &0xFF&11111111 ,也就是
在这里插入图片描述
一 &,前面的字节就没了,这样,就取到了 11011001,再转换成十进制数后就是 217。

以此类推,就先位移,再分别 &,就取出每个字节,转成成十进制数,在添加上 . 就成了 IP 地址字符串了。不知我说明白没有!

至于 IP 字符串转其他进制的数字,相信看完前面的说明,不管是要 IP 字符串转成不同进制的数字还是从数字转成 IP 字符串,大家都能类推出来。

猜你喜欢

转载自blog.csdn.net/MOESECSDN/article/details/84350502