NodeJS启动的Java进程似乎没有检测到网络接口的IPv6地址。考虑以下java代码:
public class ListAddresses {
public static void main(String args[]) throws SocketException {
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets))
displayInterfaceInformation(netint);
}
static void displayInterfaceInformation(NetworkInterface netint)
throws SocketException {
out.printf("Display name: %s\n", netint.getDisplayName());
out.printf("Name: %s\n", netint.getName());
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
out.printf("InetAddress: %s\n", inetAddress);
}
out.printf("\n");
}
}
如果我从命令行运行它,它会打印以下内容:
Display name: wlan0
Name: wlan0
InetAddress: /fe80:0:0:0:6e88:14ff:fe67:8130%3
InetAddress: /192.168.1.102
Display name: lo
Name: lo
InetAddress: /0:0:0:0:0:0:0:1%1
InetAddress: /127.0.0.1
如果我从NodeJS中启动它,如下所示:
var spawn = require('child_process').spawn;
var prc = spawn('java', ['ListAddresses']);
prc.stdout.on('data', function (data) {
console.log('' + data);
});
然后它的输出是:
Display name:
wlan0
Name: wlan0
InetAddress: /192.168.1.102
Display name: lo
Name: lo
InetAddress: /127.0.0.1
因此缺少IPv6地址。最后,如果我改变产卵的方式:
var prc = spawn('java', ['ListAddresses'], { stdio: [ 'ignore', null, null] });
然后启动的java进程正确打印所有IP地址(这似乎与https://stackoverflow.com/a/22950304/594406有关,但我不知道如何)。有人知道发生了什么事吗?我在1.8.0_66
上使用java v4.2.2
和节点Ubuntu 14.04.3 LTS
。请注意,父NodeJS进程检测到IPv6地址,如果我启动NodeJS子进程,那么它也会检测到它们。
这可能有点晚了,但我今天遇到了同样的问题,并进一步调查了一下。
这实际上不是Node.js问题,而是一些奇怪的JVM行为。原始帖子中的解决方法帮助我找到了根本原因:如果你没有将'ignore'
作为stdio
数组中的第一个条目传递,那么将使用绑定到文件描述符0(也就是stdin)的unix域套接字生成子进程。
JVM具有检测是否支持IPv6的功能,其中包括以下piece of code。代码与上面评论中的描述不符。因此,当套接字绑定到fd 0并且其类型不是IPv6套接字时,实现实际上会禁用IPv6。因此,当Node.js将unix套接字绑定到fd 0时,IPv6也会被禁用。
/*
* If fd 0 is a socket it means we've been launched from inetd or
* xinetd. If it's a socket then check the family - if it's an
* IPv4 socket then we need to disable IPv6.
*/
if (getsockname(0, &sa.sa, &sa_len) == 0) {
if (sa.sa.sa_family != AF_INET6) {
close(fd);
return JNI_FALSE;
}
}
我将此报告为Java Bug数据库的一个错误,但由于此代码已存在很长时间,因此可能不是优先考虑修复(或者这可能是有意的吗?)。
更新:现在已经确认该问题是一个错误,现在可以在Java Bug Tracker中看到。