网络字节序到主机字节序的转换Java

Network byte order to host byte order conversion Java

我正在通过 jna 使用 windows-dll 与一些加密狗服务器进行通信。 dll提供了三个函数,分别是connect、disconnect和获取dongle的连接状态。连接和断开工作。但是当我查询状态时,设备应该 return 一个我保存到 DWORD 中的 ip 地址。代码类似于,其中 DWORDByReference IpAddress 是一个输出参数:

int AwUsbGetConnectionStatus(String Hub, DWORDByReference IpAddress, IntByReference Status, DWORD Timeout, HANDLE Event); DWORD value = ipAddress.getValue();

dll 的规范说明:"IpAddress is in host byte order and can be converted to TCP/IP network byte order using the WinSock htonl function."

在另一个线程中,我读到 java 等同于 htonl 是:

static int htonl(int val) { return ByteBuffer.allocate(4).putInt(val) .order(ByteOrder.nativeOrder()).getInt(0); }

但问题是,我得到了奇怪的值。但不知何故,它们确实对应于 ip 地址的假定值。
比如原来的IP是:192.168.102.118
它 returns 1986439360
当我用上面的方法转换它时,它是-1062705546.
但我想正确转换后应该是192168102118

我试过的另一个 IP 地址是: 192.168.102.112 为此我得到 1885776064 当我将其转换为 -106270552

因此原始地址和转换后的 IP 地址之间的差值仍然是 6。我用不同的 Ips 尝试了这个,Ips 之间的差异总是与假定值相匹配。 那么有人知道吗,如果我将值转换为 dll 函数 returns 的方式有问题,或者当我获取 DWORD 参数的值时甚至会出现问题吗?

您需要将十进制值 (-1062705546) 分解为组成它的 4 个字节。如果这样做,您将得到十六进制表示法:

C0 A8 66 76

对应192.168.102.118.

该方法返回的值是正确的。 在 Java 中,所有整数都是有符号的。它没有无符号类型。

对于您的 IP 192.168.102.118,十六进制数为 C0 A8 66 76,转换为有符号整数为 -1062705546

您应该设置 将 little-endian 地址放入其中之前的顺序。

并且(从您的评论 "i guess it should be 192168102118 when converted properly" 看来)您想要 dotted-quad 输出;为此,使用字节数组可能更自然:

static byte[] htoip(int ipv4) {
  return ByteBuffer.wrap(new byte[4])
                   .order(ByteOrder.nativeOrder())
                   .putInt(ipv4)
                   .array();
}

这个结果适合传给InetAddress.getByAddress()

虽然这不是反转 4 个字节的最简单方法,但它使用 ByteOrder.nativeOrder() 使其可移植并且 future-proof.