Conversion IPv6 to long and long to IPv6

坚强是说给别人听的谎言 提交于 2019-11-27 14:41:34

问题


How should I perform conversion from IPv6 to long and vice versa?

So far I have:

    public static long IPToLong(String addr) {
            String[] addrArray = addr.split("\\.");
            long num = 0;
            for (int i = 0; i < addrArray.length; i++) {
                    int power = 3 - i;

                    num += ((Integer.parseInt(addrArray[i], 16) % 256 * Math.pow(256, power)));
            }
            return num;
    }

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

    }

Is it correct solution or I missed something?

(It would be perfect if the solution worked for both ipv4 and ipv6)


回答1:


An IPv6 address is a 128-bit number as described here. A long in Java is represented on 64 bits, so you need another structure, like a BigDecimal or two longs (a container with an array of two longs or simply an array of two longs) in order to store an IPv6 address.

Below is an example (just to provide you an idea):

public class Asd {

public static long[] IPToLong(String addr) {
    String[] addrArray = addr.split(":");//a IPv6 adress is of form 2607:f0d0:1002:0051:0000:0000:0000:0004
    long[] num = new long[addrArray.length];

    for (int i=0; i<addrArray.length; i++) {
        num[i] = Long.parseLong(addrArray[i], 16);
    }
    long long1 = num[0];
    for (int i=1;i<4;i++) {
        long1 = (long1<<16) + num[i];
    }
    long long2 = num[4];
    for (int i=5;i<8;i++) {
        long2 = (long2<<16) + num[i];
    }

    long[] longs = {long2, long1};
    return longs;
}


public static String longToIP(long[] ip) {
    String ipString = "";
    for (long crtLong : ip) {//for every long: it should be two of them

        for (int i=0; i<4; i++) {//we display in total 4 parts for every long
            ipString = Long.toHexString(crtLong & 0xFFFF) + ":" + ipString;
            crtLong = crtLong >> 16;
        }
    }
    return ipString;

}

static public void main(String[] args) {
    String ipString = "2607:f0d0:1002:0051:0000:0000:0000:0004";
    long[] asd = IPToLong(ipString);

    System.out.println(longToIP(asd));
}

}




回答2:


You can also use java.net.InetAddress
It works with both ipv4 and ipv6 (all formats)

public static BigInteger ipToBigInteger(String addr) {
    InetAddress a = InetAddress.getByName(addr)
    byte[] bytes = a.getAddress()
    return new BigInteger(1, bytes)
}



回答3:


An IPv6 address can not be stored in long. You can use BigInteger instead of long.

public static BigInteger ipv6ToNumber(String addr) {
    int startIndex=addr.indexOf("::");

    if(startIndex!=-1){


        String firstStr=addr.substring(0,startIndex);
        String secondStr=addr.substring(startIndex+2, addr.length());


        BigInteger first=ipv6ToNumber(firstStr);

        int x=countChar(addr, ':');

        first=first.shiftLeft(16*(7-x)).add(ipv6ToNumber(secondStr));

        return first;
    }


    String[] strArr = addr.split(":");

    BigInteger retValue = BigInteger.valueOf(0);
    for (int i=0;i<strArr.length;i++) {
        BigInteger bi=new BigInteger(strArr[i], 16);
        retValue = retValue.shiftLeft(16).add(bi);
    }
    return retValue;
}


public static String numberToIPv6(BigInteger ipNumber) {
    String ipString ="";
    BigInteger a=new BigInteger("FFFF", 16);

        for (int i=0; i<8; i++) {
            ipString=ipNumber.and(a).toString(16)+":"+ipString;

            ipNumber = ipNumber.shiftRight(16);
        }

    return ipString.substring(0, ipString.length()-1);

}

public static int countChar(String str, char reg){
    char[] ch=str.toCharArray();
    int count=0;
    for(int i=0; i<ch.length; ++i){
        if(ch[i]==reg){
            if(ch[i+1]==reg){
                ++i;
                continue;
            }
            ++count;
        }
    }
    return count;
}



回答4:


Vinod's answer is right. But there are still some things that can be improved.(Sorry I can not add a comment below Vinod's answer because I am new here.)

First, in method 'countChar', 'continue' should be replaced by 'break'.

And second, Some boundary conditions must be considered.

public static BigInteger ipv6ToNumber(String addr) {
    int startIndex = addr.indexOf("::");
    if (startIndex != -1) {
        String firstStr = addr.substring(0, startIndex);
        String secondStr = addr.substring(startIndex + 2, addr.length());
        BigInteger first = new BigInteger("0");
        BigInteger second = new BigInteger("0");
        if (!firstStr.equals("")) {
            int x = countChar(addr, ':');
            first = ipv6ToNumber(firstStr).shiftLeft(16 * (7 - x));
        }
        if (!secondStr.equals("")) {
            second = ipv6ToNumber(secondStr);
        }
        first = first.add(second);
        return first;
    }

    String[] strArr = addr.split(":");
    BigInteger retValue = BigInteger.valueOf(0);
    for (int i = 0; i < strArr.length; i++) {
        BigInteger bi = new BigInteger(strArr[i], 16);
        retValue = retValue.shiftLeft(16).add(bi);
    }
    return retValue;
}

public static int countChar(String str, char reg){
    char[] ch=str.toCharArray();
    int count=0;
    for(int i=0; i<ch.length; ++i){
        if(ch[i]==reg){
            if(ch[i+1]==reg){
                ++i;
                break;
            }
            ++count;
        }
    }
    return count;
}


来源:https://stackoverflow.com/questions/17875728/conversion-ipv6-to-long-and-long-to-ipv6

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!