在Java中将IP地址在IPv4和数字格式之间转换

6

IPv4地址可以有多种表示形式:字符串(a.b.c.d)或数字(作为32位无符号整数)。 (可能还有其他形式,但我会忽略它们。)

Java(8)是否有内置支持,简单易用且无需网络访问,以在这些格式之间进行转换?

我需要像这样的东西:

long ip = toNumerical("1.2.3.4"); // returns 0x0000000001020304L
String ipv4 = toIPv4(0x0000000001020304L); // returns "1.2.3.4"

如果Java中没有内置此类函数,请随意建议其他解决方案。
谢谢。

请参考类似问题:https://dev59.com/g2ct5IYBdhLWcg3wetYo#12057944 - gparis
4个回答

11

可以使用InetAddress来完成。

//Converts a String that represents an IP to an int.
InetAddress i = InetAddress.getByName(IPString);
int intRepresentation = ByteBuffer.wrap(i.getAddress()).getInt();

//This converts an int representation of ip back to String
i = InetAddress.getByName(String.valueOf(intRepresentation));
String ip = i.getHostAddress();

5
使用int可以吗?IP是unsigned int!使用long会更安全吗?对应于255.0.0.0int是什么?数值IP可以为负数吗?我问了太多问题了吗?:)谢谢 - Costin
此代码将在行上抛出java.net.UnknownHostException:无法解析主机:InetAddress.getByName(...)。请参阅我的答案,以正确地将字符串IP地址转换为整数并再次转换为字符串。 - Kirill Karmazin
1
代码在将“176.218.221.21”转换为整数时失败,因为整数是带符号数据类型。 - Halil
1
@QuakeCore 请编辑您的答案,并使用Integer.toUnsignedLong方法包装ByteBuffer,以支持无符号整数结果。long longRepresentation = Integer.toUnsignedLong(ByteBuffer.wrap(i.getAddress()).getInt()); - BeardOverflow
2
@Costin 使用com.google.common.net.InetAddresses.forString(String ipString)来避免任何尝试进行网络访问(guava包)。原始的java.net.InetAddress.getByName(String ipString)会对本地地址进行一些DNS查找。 - BeardOverflow
显示剩余3条评论

6

这里有一种将IP地址转换为数字的方法Convert IP to Number。我发现这是在Java中完成此任务的有效方法。

public long ipToLong(String ipAddress) {

    String[] ipAddressInArray = ipAddress.split("\\.");

    long result = 0;
    for (int i = 0; i < ipAddressInArray.length; i++) {

        int power = 3 - i;
        int ip = Integer.parseInt(ipAddressInArray[i]);
        result += ip * Math.pow(256, power);

    }

    return result;
  }

这也是您在Scala中实现它的方法。
  def convertIPToLong(ipAddress: String): Long = {

    val ipAddressInArray = ipAddress.split("\\.")
    var result = 0L

    for (i  <- 0  to ipAddressInArray.length-1) {
      val power = 3 - i
      val ip = ipAddressInArray(i).toInt
      val longIP = (ip * Math.pow(256, power)).toLong
      result = result +longIP
    }
    result
  }

4

QuakeCore提供的代码片段在将其转换回字符串的部分会抛出“java.net.UnknownHostException:无法解析主机”的异常。

但是利用InetAddress类的想法是正确的。这是你想要做的:

            try {
                InetAddress inetAddressOrigin = InetAddress.getByName("78.83.228.120");
                int intRepresentation = ByteBuffer.wrap(inetAddressOrigin.getAddress()).getInt(); //1314120824

                ByteBuffer buffer = ByteBuffer.allocate(4);
                buffer.putInt(intRepresentation);
                byte[] b = buffer.array();

                InetAddress inetAddressRestored = InetAddress.getByAddress(b);
                String ip = inetAddressRestored.getHostAddress();//78.83.228.120

            } catch (UnknownHostException e) {
                e.printStackTrace(); //
            }

附注:如果你要为一些ip地址列表执行此操作,请验证它们是否有子网掩码,例如:78.83.228.0/8 在这种情况下,你需要将其展开:78.83.228.0/8 => 78.83.228.0 78.83.228.1 78.83.228.2 78.83.228.3 78.83.228.4 78.83.228.5 78.83.228.6 78.83.228.7


1
尝试不错,但这里似乎有一些错误/问题。请使用以下IP地址测试您的代码:191.255.255.254252.250.250.254255.250.250.254。您将获得有符号整数。例如,第一个IP地址(191.255.255.254)应该转换为3221225470,但实际上它给出了-1073741826 - papigee

2
我建议如下:

long ip2long() {
    ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.BIG_ENDIAN);
    buffer.put(new byte[] { 0,0,0,0 });
    buffer.put(socket.getInetAddress().getAddress());
    buffer.position(0);
    return buffer.getLong();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接