NodeJS生成的Java进程中的网络接口的IP地址

问题描述 投票:2回答:1

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

java node.js
1个回答
2
投票

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

这实际上不是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中看到。

© www.soinside.com 2019 - 2024. All rights reserved.