ip地址和整数之间的转换

2,493次阅读
没有评论

一、应用范围
一般用在登录限制、查找IP所在城市等需求中,windows的ping命令也支持整数形式的IP。

二、关键技术点
将IP地址转化成整数的方法如下:
1、通过String的indexOf方法找出IP字符串中的点"."的位置。
2、根据点的位置,使用String的substring方法把IP字符串分成4段。
3、使用Long的parseLong方法把子段转化成一个3位整数。
4、通过左移位操作(<<)给每一段的数字加权,第一段的权为2的24次方,第二段的权为2的16次方,第三段的权为2的8次方,最后一段的权为1 将整数形式的IP地址转化成字符串的方法如下: 1、将整数值进行右移位操作(>>>),右移24位,右移时高位补0,得到的数字即为第一段IP。
2、通过与操作符(&)将整数值的高8位设为0,再右移16位,得到的数字即为第二段IP。
3、通过与操作符吧整数值的高16位设为0,再右移8位,得到的数字即为第三段IP。
4、通过与操作符吧整数值的高24位设为0,得到的数字即为第四段IP。

原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成
一个长整数。
举例:一个ip地址为10.0.3.193
每段数字 相对应的二进制数
10 00001010
0 00000000
3 00000011
193 11000001
组合起来即为:00001010 00000000 00000011 11000001,转换为10进制数就是:167773121,即该IP地址转换后的数字就是它了。

在上面的方法中,原理都是一样的。我用到了位移操作,因为它就是操作的二进制数,使用位移操作很方面、直观。
Long.parseLong(token.nextToken())<<24 就是把第一段数字表示的二进制数左移了24位,(记住:按位操作符都操作的整数的二进制数) 得到00001010 00000000 00000000 00000000; 依次类推: Long.parseLong(token.nextToken())<<16,得到00000000 00000000 00000000 00000000; Long.parseLong(token.nextToken())<<8,得到00000000 00000000 00000011 00000000; Long.parseLong(token.nextToken()),最低位不用移动,得到00000000 00000000 00000000 11000001; 把这四个二进制数转换为整数后相加和00001010 00000000 00000011 11000001表示的二进制数是一样的(这个就不多说了,明白人一看就知道了)。 java代码:

/** *//**  
 * 文件名:IP2Long.java  
 */  
package book.oo.String;   
  
/** *//**  
 * @author joe  
 *  
 */  
public class IP2Long ...{   
       
    //将127.0.0.1形式的IP地址转换成十进制整数,这里没有进行任何错误处理   
    public static long ipToLong(String strIp) ...{   
        long[] ip = new long[4];   
        //先找到IP地址字符串中.的位置   
        int position1 = strIp.indexOf(".");   
        int position2 = strIp.indexOf(".", position1 + 1);   
        int position3 = strIp.indexOf(".", position2 + 1);   
        //将每个.之间的字符串转换成整型   
        ip[0] = Long.parseLong(strIp.substring(0, position1));   
        ip[1] = Long.parseLong(strIp.substring(position1+1, position2));   
        ip[2] = Long.parseLong(strIp.substring(position2+1, position3));   
        ip[3] = Long.parseLong(strIp.substring(position3+1));   
        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];   
    }   
       
    //将十进制整数形式转换成127.0.0.1形式的ip地址   
    public static String longToIP(long longIp) ...{   
        StringBuffer sb = new StringBuffer("");   
        //直接右移24位   
        sb.append(String.valueOf((longIp >>> 24)));   
        sb.append(".");   
        //将高8位置0,然后右移16位   
        sb.append(String.valueOf((longIp & 0x00FFFFFF) >>> 16));   
        sb.append(".");   
        //将高16位置0,然后右移8位   
        sb.append(String.valueOf((longIp & 0x0000FFFF) >>> 8));   
        sb.append(".");   
        //将高24位置0   
        sb.append(String.valueOf((longIp & 0x000000FF)));   
        return sb.toString();   
    }   
    /** *//**  
     * @param args  
     */  
    public static void main(String[] args) ...{   
        String ipStr = "192.168.0.1";   
        long longIp = IP2Long.ipToLong(ipStr);   
        System.out.println("192.168.0.1 的整数形式为:" + longIp);   
        System.out.println("整数" + longIp + "转化成字符串IP地址:"  
                + IP2Long.longToIP(longIp));   
        //ip地址转化成二进制形式输出   
        System.out.println("192.168.0.1 的二进制形式为:" + Long.toBinaryString(longIp));   
  
    }   
}

php实现

function get_real_ip(){
	$ip=false;
	if(!empty($_SERVER["HTTP_CLIENT_IP"])){
		$ip=$_SERVER["HTTP_CLIENT_IP"];
	}
	if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
		$ips=explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']);
		if ($ip){
			array_unshift($ips,$ip);
			$ip=FALSE;
		}
		for($i=0;$i

$2 :长整数转换为Ip的代码:

Java代码
public static String longToIp(long ipLong){
StringBuilder sb = new StringBuilder();
sb.append(ipLong>>>24);sb.append(".");
sb.append(String.valueOf((ipLong&0x00FFFFFF)>>>16));sb.append(".");
sb.append(String.valueOf((ipLong&0x0000FFFF)>>>8));sb.append(".");
sb.append(String.valueOf(ipLong&0x000000FF));
return sb.toString();
}

public static String longToIp(long ipLong){
StringBuilder sb = new StringBuilder();
sb.append(ipLong>>>24);sb.append(".");
sb.append(String.valueOf((ipLong&0x00FFFFFF)>>>16));sb.append(".");
sb.append(String.valueOf((ipLong&0x0000FFFF)>>>8));sb.append(".");
sb.append(String.valueOf(ipLong&0x000000FF));
return sb.toString();
}
原理:很简单的,就是$1的“反编码”(就这样先叫着),先把这个长整数转换成一个32位的二进制数。从左到右,每8位
进行一下分割,就得到4段8位的二进制数,把这些二进制数转换成整数然后加上"."就是这个ip地址了。
举例:167773121
二进制表示形式为:00001010 00000000 00000011 11000001
分割成四段:00001010,00001010,00000011,11000001,分别转换为整数后加上“.”就得到了10.0.3.193。
每段怎么计算为整数的呢,比如00001010,一个整数是32位的整数,所以前面全部补0(也就是说把该段的8位看成是低位数字,高位全部补0,得到一个32位的二进制数,即为一个整数的二进制数表示形式),由此可以得到
00000000 00000000 00000000 00001010,就是传说中的10,其他三个数字也就相继可以得到了。

上面的longToIp方法使用也是与$1中位移操作正好相反。
先得到第一段(它是二进制数的左边)的整数,那个长整型的二进制数字无符号左移24位(正好是前面都补0),得到一个二
进制数即为最高位的数字。即可以用位移实现ipLong>>>24(>>>操作的是ipLong的二进制数);
想得到第二段,就要把ipLong表示的二进制数进行无符号左移16位,但是它的左边不一定为0(还有第一段数字的二进制数
呢),所以在移位之前先把前面的的8位置为0,就可以用ipLong&0x00FFFFFF表示。
0x00FFFFFF是什么呢?为什么要&0x00FFFFFF呢?

0x00FFFFFF是一个16进制数,它的二进制表示形式为00000000 11111111 11111111 11111111,结合前篇博文【传说中的Java基础东西(按位操作运算)】的&用法,你就很清楚为啥要&0x00FFFFFF了,它可以使前8为置为0,后16位是1或者0还是不变的。
然后就可以肆无忌惮的把ipLong表示的二进制数进行无符号的左移16位。
ipLong&0x00FFFFFF 可以得到00000000 00000000 00000011 11000001,然后让它>>>16位,
得到00000000 00000000 00000000 00000000,即为第二段的数字0、
依次类推、
最后一段直接把前24位都置为0,然后计算出来的整数即为最后一段的值了。

OK,写了那么多,其实就是一个简单的把ip转换为整数,中间主要是操作了二进制数,想想也很简单,为啥以前咱就不会
呢。想了一下,原来还是自己的计算机基础的二进制没有学好,后悔啊,又浪费我的生命去重新学习....

正文完
 

公众号