NodeJS

时间:2015-12-05 16:53:06

标签: java node.js

由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子进程,那么它也会检测到它们。

1 个答案:

答案 0 :(得分:2)

这可能有点晚了,但是我今天遇到了同样的问题,并进行了进一步调查。

这实际上不是Node.js问题,而是一些怪异的JVM行为。原始帖子中的解决方法帮助我找到了根本原因:如果您不通过'ignore'作为stdio数组中的第一个条目,则将生成带有绑定到file的unix域套接字的子进程。描述符0(又称stdin)。

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中看到。