从 127.0.0.1 到 2130706433,然后再返回

Posted

技术标签:

【中文标题】从 127.0.0.1 到 2130706433,然后再返回【英文标题】:Going from 127.0.0.1 to 2130706433, and back again 【发布时间】:2011-01-15 12:31:16 【问题描述】:

使用标准 Java 库,从 IPV4 地址的点分字符串表示 ("127.0.0.1") 到等效整数表示 (2130706433) 的最快方法是什么。

相应地,反转上述操作的最快方法是什么 - 从整数2130706433 到字符串表示"127.0.0.1"

【问题讨论】:

【参考方案1】:

您也可以使用Google Guava InetAddress 类

String ip = "192.168.0.1";
InetAddress addr = InetAddresses.forString(ip);
// Convert to int
int address = InetAddresses.coerceToInteger(addr);
// Back to str 
String addressStr = InetAddresses.fromInteger(address));

【讨论】:

我认为这是最简单的。除非您关心微秒级性能,否则请使用处理所有字节序和符号的标准库【参考方案2】:

使用the IPAddress Java library 很简单,每个方向一行代码。 免责声明:我是该库的项目经理。

    IPv4Address loopback = new IPAddressString("127.0.0.1").getAddress().toIPv4();
    System.out.println(loopback.intValue());
    IPv4Address backAgain = new IPv4Address(loopback.intValue());
    System.out.println(backAgain);

输出:

    2130706433
    127.0.0.1

【讨论】:

【参考方案3】:

另一种方式:

public static 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;
  

【讨论】:

【参考方案4】:

字符串转整数:

int pack(byte[] bytes) 
  int val = 0;
  for (int i = 0; i < bytes.length; i++) 
    val <<= 8;
    val |= bytes[i] & 0xff;
  
  return val;


pack(InetAddress.getByName(dottedString).getAddress());

整数转字符串:

byte[] unpack(int bytes) 
  return new byte[] 
    (byte)((bytes >>> 24) & 0xff),
    (byte)((bytes >>> 16) & 0xff),
    (byte)((bytes >>>  8) & 0xff),
    (byte)((bytes       ) & 0xff)
  ;



InetAddress.getByAddress(unpack(packedBytes)).getHostAddress()

【讨论】:

127.0.0.1 给出 2130706433,但 255.255.255.255 没有给出 4294967295。签名与未签名的问题? 以无符号形式打印,将结果转换为 long 并屏蔽高位:((long)packedBytes)&amp;0xffffffff 字节在Java中最多为2^7-1,这样每个字节将无法显示任何大于127的整数。正确的做法是使用int来存储数字。跨度> 【参考方案5】:

如果您需要学习长手数学,您可以使用 Substr 删除八位字节。 将表示类的第一个八位字节乘以 (256*256*256) 或 (2^24) 秒乘以 (256*256) (2^16) 第三乘以 (256) (2^8) 第四乘以 1 或 (2^0)

127 * (2^24) + 0 *(2^16) + 0 * (2^8) + 1 * (2^0) 2130706432 + 0 + 0 + 1 = 2130706433

【讨论】:

【参考方案6】:

我修改了我原来的答案。在 Sun 的 InetAddress 实现中,hashCode 方法生成 IPv4 地址的整数表示,但正如评论者正确指出的那样,JavaDoc 不能保证这一点。因此,我决定改用ByteBuffer类来计算IPv4地址的值。

import java.net.InetAddress;
import java.nio.ByteBuffer;

// ...

try 
    // Convert from integer to an IPv4 address
    InetAddress foo = InetAddress.getByName("2130706433");
    String address = foo.getHostAddress();
    System.out.println(address);

    // Convert from an IPv4 address to an integer
    InetAddress bar = InetAddress.getByName("127.0.0.1");
    int value = ByteBuffer.wrap(bar.getAddress()).getInt();
    System.out.println(value);

 catch (Exception e) 
    e.printStackTrace();

输出将是:

127.0.0.1
2130706433

【讨论】:

hashCode() 是否明确定义为进行 4 字节到 int 的转换?如果不是,我怀疑是这样。请注意,解释总是好的。 IP地址到int的映射需要双射。 hashCode 不保证这一点。 这应该被否决。 Javadocs 中没有任何内容可以保证这种行为,它恰好是目前(明智的)Sun 实现。 Sun 可以将其更改为仅返回一个常量,它仍然可以正常运行,但您的示例会失败。 您是正确的,InetAddress 的 hashCode() 方法没有指定如何计算散列。我将把答案留在这里,因为它使用 InetAddress 的标准实现“工作”。 我已根据您的担忧更新了我的答案。我的示例现在使用 ByteBuffer 类来计算 IPv4 地址的整数值,而不是依赖 InetAddress 的 hashCode 方法。【参考方案7】:

我没试过。性能,但最简单的方法可能是使用 NIO ByteBuffer。

例如

 byteBuffer.put(integer).array();

会返回一个表示整数的字节数组。您可能需要修改字节顺序。

【讨论】:

为什么不直接选择一个字节顺序并使其成为 ByteBuffer 的字节顺序?这样您就不必担心不同机器上的不同默认字节顺序。编辑:没关系,默认是大端。

以上是关于从 127.0.0.1 到 2130706433,然后再返回的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 Magento-1.9.4 中的“无法将 VCL 应用到 127.0.0.1:6082:无法从 Varnish 读取响应代码”错误

保存Ajax但不将CORS cookie从127.0.0.1发送到服务

如何强制 where 子句中的函数在 oracle 中执行一次?

在 127.0.0.1:3306 上添加客户端到服务器端口转发规则失败

如何同步到redis

localhost与127.0.0.1的区别