Java:将int转换为InetAddress

31
我有一个包含网络字节顺序IP地址的int,我想将其转换为InetAddress对象。我看到有一个接受byte[]参数的InetAddress构造函数,是否需要先将int转换为byte[],还是有其他方法可以实现呢?

你能提供一个示例展示这个整数的形式,以及它应该是什么样的字符串表示吗?我无法想象如何将255255255255放入一个整数中,这会造成溢出。 - BalusC
2
@BalusC:IPv4地址只是一个32位的数字,通常表示为4个8位值。但是这些信息在32位中完全适合。 - skaffman
4
请记住,如果您想支持IPv6,就不能使用单个整数来处理IP地址。 - iny
10个回答

30

测试并且工作正常:

int ip  = ... ;
String ipStr = 
  String.format("%d.%d.%d.%d",
         (ip & 0xff),   
         (ip >> 8 & 0xff),             
         (ip >> 16 & 0xff),    
         (ip >> 24 & 0xff));

7
这会将字节顺序转换错误。对于小端整数,它是有效的,但问题要求按“网络字节顺序”排序,该顺序为大端,Java中的整数也是如此。正确的顺序应该是:String.format("%d.%d.%d.%d", (ip >> 24 & 0xff), (ip >> 16 & 0xff), (ip >> 8 & 0xff), (ip & 0xff)); - Mr. Kevin Thomas

17

这应该可以工作:

int ipAddress = ....
byte[] bytes = BigInteger.valueOf(ipAddress).toByteArray();
InetAddress address = InetAddress.getByAddress(bytes);

你可能需要交换字节数组的顺序,我无法确定数组是否以正确的顺序生成。


2
确实仍需要交换字节数组的顺序。然而,事实证明我的输入实际上是按主机顺序排列的!谢谢。 - kdt
15
对于IP地址范围在0.0.0.0 - 0.127.255.255和255.128.0.0 - 255.255.255.255之间的情况,此方法无法使用:bytes数组将少于4个元素。 - user85421
@NikolayKuznetsov 因为这些范围会导致字节数组的大小小于等于3,而InetAddress要求数组的大小为4或16。 - aij
3
危险。例如对于0.0.0.0,无法使用。不可靠! - toom

4
我认为这段代码更简单:
static public byte[] toIPByteArray(int addr){
        return new byte[]{(byte)addr,(byte)(addr>>>8),(byte)(addr>>>16),(byte)(addr>>>24)};
    }

static public InetAddress toInetAddress(int addr){
    try {
        return InetAddress.getByAddress(toIPByteArray(addr));
    } catch (UnknownHostException e) {
        //should never happen
        return null;
    }
}

3
这基本正确,但你把字节的顺序搞反了:http://docs.oracle.com/javase/7/docs/api/java/net/InetAddress.html#getByAddress(byte[])。 - aij

4
如果你使用Google的Guava库,InetAddresses.fromInteger正好满足你的需求。Api文档在这里
如果你想编写自己的转换函数,可以像@aalmeida建议的那样做,但一定要按正确的顺序(从最高有效字节开始)放置字节。

你的回答中的链接已经失效。 - redbeam_
@redbeam_ 已更新。 - aij

2
public static byte[] int32toBytes(int hex) {
    byte[] b = new byte[4];
    b[0] = (byte) ((hex & 0xFF000000) >> 24);
    b[1] = (byte) ((hex & 0x00FF0000) >> 16);
    b[2] = (byte) ((hex & 0x0000FF00) >> 8);
    b[3] = (byte) (hex & 0x000000FF);
    return b;

}

您可以使用这个函数将整数转换为字节。

1

我的声望不够,无法在skaffman的回答下发表评论,所以我会将这个作为一个单独的回答。

skaffman提出的解决方案是正确的,但有一个例外。BigInteger.toByteArray()返回一个字节数组,其中可能包含一个前导符号位。

byte[] bytes = bigInteger.toByteArray();

byte[] inetAddressBytes;

// Should be 4 (IPv4) or 16 (IPv6) bytes long
if (bytes.length == 5 || bytes.length == 17) {
    // Remove byte with most significant bit.
    inetAddressBytes = ArrayUtils.remove(bytes, 0);
} else {
    inetAddressBytes = bytes;
}

InetAddress address = InetAddress.getByAddress(inetAddressBytes);

PS 上面的代码使用了 Apache Commons Lang 中的 ArrayUtils。


1
我认为额外的前导符号位不会成为问题,但如果地址在0.0.0.0-0.127.255.255和255.128.0.0-255.255.255.255范围内,则缺少字节。 - user85421
抱歉,我在这个领域并不是专家。你能详细解释一下你的评论吗?恐怕我没能理解重点(也有可能我的代码中出现了错误 ;) )。 - Dennis Laumen
@DennisLaumen 你可以尝试输入0、42或-42。你应该得到0.0.0.0、0.0.0.42和255.255.255.214。但实际上你会得到一个异常。请参考https://en.wikipedia.org/wiki/Twos_complement。 - aij

1
使用Google Guava:
byte[] bytes = Ints.toByteArray(ipAddress);
InetAddress address = InetAddress.getByAddress(bytes);

0

由于注释无法格式化,让我发布由@Mr.KevinThomas提供的代码:

if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
    ipAddress = Integer.reverseBytes(ipAddress);
}
sReturn = String.format(Locale.US, "%d.%d.%d.%d", (ipAddress >> 24 & 0xff), (ipAddress >> 16 & 0xff), (ipAddress >> 8 & 0xff), (ipAddress & 0xff));

它已在Android上进行了测试。


-1

这可能有效,请尝试


public static String intToIp(int i) {
        return ((i >> 24 ) & 0xFF) + "." +
               ((i >> 16 ) & 0xFF) + "." +
               ((i >>  8 ) & 0xFF) + "." +
               ( i        & 0xFF);
    }

3
他要求将整数转换为字节数组,而不是字符串。此外,你的话“this may work try”让我觉得你只是盲目地通过谷歌搜索并复制粘贴随机函数?为什么? - BalusC

-1
  public InetAddress intToInetAddress(Integer value) throws UnknownHostException
  {
    ByteBuffer buffer = ByteBuffer.allocate(32);
    buffer.putInt(value);
    buffer.position(0);
    byte[] bytes = new byte[4];
    buffer.get(bytes);
    return InetAddress.getByAddress(bytes);
  }

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