如果Java中的DNS无法解析,如何获取本地主机名?

发布于 2024-11-08 07:28:27 字数 652 浏览 0 评论 0原文

这听起来像是以前应该问过的问题,而且确实如此,但我希望获取机器的本地主机名和 IP 地址,即使它无法通过 DNS(在 Java 中)解析。

我可以通过迭代 NetworkInterfaces.getNetworkInterfaces() 来获取本地 IP 地址,而无需解析。

我发现的这个问题的任何答案都表明使用 getLocalHost(),

InetAddress localhost = java.net.InetAddress.getLocalHost();
hostName = localhost.getHostName();

但如果主机名无法通过 DNS 解析,则会抛出 UnknownHostException

如果没有在幕后进行 DNS 查找,是否无法获取本地主机名?

编辑:检索到的IP地址是10.4.168.23 例外情况是 java.net.UnknownHostException: cms1.companyname.com: cms1.companyname.com(主机名已更改为伪匿名),并且主机文件不包含主机名。但它确实知道它的主机名,所以我不确定为什么我无法在不抛出异常的情况下获取它。

This sounds like something that should have been asked before, and it has sort of, but I'm looking to get the local hostname and IP addresses of a machine even when it is not resolvable through DNS (in Java).

I can get the local IP addresses without resolution by iterating through NetworkInterfaces.getNetworkInterfaces().

Any answers to this question I've found indicate to use getLocalHost()

InetAddress localhost = java.net.InetAddress.getLocalHost();
hostName = localhost.getHostName();

but this throws an UnknownHostException if the hostname isn't resolvable through DNS.

Is there no way to get the local hostname without a DNS lookup happening behind the scenes?

edit: the IP address retrieved is 10.4.168.23
The exception is java.net.UnknownHostException: cms1.companyname.com: cms1.companyname.com (hostname changed for pseudo-anonymity), and the hosts file does not contain the hostname. But it does know its hostname, so I'm not sure why I can't get it without an exception being thrown.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

污味仙女 2024-11-15 07:28:27

是的,Java 中应该有一种无需借助名称服务查找即可获取主机名的方法,但不幸的是没有。

然而,您可以这样做:

if (System.getProperty("os.name").startsWith("Windows")) {
    // Windows will always set the 'COMPUTERNAME' variable
    return System.getenv("COMPUTERNAME");
} else {
    // If it is not Windows then it is most likely a Unix-like operating system
    // such as Solaris, AIX, HP-UX, Linux or MacOS.

    // Most modern shells (such as Bash or derivatives) sets the 
    // HOSTNAME variable so lets try that first.
    String hostname = System.getenv("HOSTNAME");
    if (hostname != null) {
       return hostname;
    } else {

       // If the above returns null *and* the OS is Unix-like
       // then you can try an exec() and read the output from the 
       // 'hostname' command which exist on all types of Unix/Linux.

       // If you are an OS other than Unix/Linux then you would have 
       // to do something else. For example on OpenVMS you would find 
       // it like this from the shell:  F$GETSYI("NODENAME") 
       // which you would probably also have to find from within Java 
       // via an exec() call.

       // If you are on zOS then who knows ??

       // etc, etc
    }
}

这将让您在传统的 Sun JDK 平台(Windows、Solaris、Linux)上获得您想要的 100% 的结果,但如果您的操作系统更加奇特(从 Java 的角度来看),那么就变得不那么容易了。请参阅代码示例中的注释。

我希望有更好的方法。

Yes, there should be a way in Java to get the hostname without resorting to name service lookups but unfortunately there isn't.

However, you can do something like this:

if (System.getProperty("os.name").startsWith("Windows")) {
    // Windows will always set the 'COMPUTERNAME' variable
    return System.getenv("COMPUTERNAME");
} else {
    // If it is not Windows then it is most likely a Unix-like operating system
    // such as Solaris, AIX, HP-UX, Linux or MacOS.

    // Most modern shells (such as Bash or derivatives) sets the 
    // HOSTNAME variable so lets try that first.
    String hostname = System.getenv("HOSTNAME");
    if (hostname != null) {
       return hostname;
    } else {

       // If the above returns null *and* the OS is Unix-like
       // then you can try an exec() and read the output from the 
       // 'hostname' command which exist on all types of Unix/Linux.

       // If you are an OS other than Unix/Linux then you would have 
       // to do something else. For example on OpenVMS you would find 
       // it like this from the shell:  F$GETSYI("NODENAME") 
       // which you would probably also have to find from within Java 
       // via an exec() call.

       // If you are on zOS then who knows ??

       // etc, etc
    }
}

and that will get you 100% what you want on the traditional Sun JDK platforms (Windows, Solaris, Linux) but becomes less easy if your OS is more excotic (from a Java perspective). See the comments in the code example.

I wish there was a better way.

唔猫 2024-11-15 07:28:27

这个问题很老了,但不幸的是仍然相关,因为在 Java 中获取机器的主机名仍然不是小事。这是我的解决方案,在不同的系统上运行了一些测试:

public static void main(String[] args) throws IOException {
        String OS = System.getProperty("os.name").toLowerCase();

        if (OS.indexOf("win") >= 0) {
            System.out.println("Windows computer name throguh env:\"" + System.getenv("COMPUTERNAME") + "\"");
            System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
        } else {
            if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
                System.out.println("Linux computer name throguh env:\"" + System.getenv("HOSTNAME") + "\"");
                System.out.println("Linux computer name through exec:\"" + execReadToString("hostname") + "\"");
                System.out.println("Linux computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
            }
        }
    }

    public static String execReadToString(String execCommand) throws IOException {
        Process proc = Runtime.getRuntime().exec(execCommand);
        try (InputStream stream = proc.getInputStream()) {
            try (Scanner s = new Scanner(stream).useDelimiter("\\A")) {
                return s.hasNext() ? s.next() : "";
            }
        }
    }

不同操作系统的结果:

OpenSuse 13.1

Linux computer name throguh env:"machinename"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:""

Ubuntu 14.04 LTS
这有点奇怪,因为 echo $HOSTNAME 返回正确的主机名,但 System.getenv("HOSTNAME") 没有(但这可能只是我的环境的问题) ):

Linux computer name throguh env:"null"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:"machinename
"

Windows 7

Windows computer name throguh env:"MACHINENAME"
Windows computer name through exec:"machinename
"

机器名称已被替换为(部分)匿名化,但我保留了大小写和结构。请注意执行 hostname 时的额外换行符,在某些情况下您可能需要考虑它。

This question is old, but unfortunately still relevant since it's still not trivial to get a machine's host name in Java. Here's my solution with some test runs on different systems:

public static void main(String[] args) throws IOException {
        String OS = System.getProperty("os.name").toLowerCase();

        if (OS.indexOf("win") >= 0) {
            System.out.println("Windows computer name throguh env:\"" + System.getenv("COMPUTERNAME") + "\"");
            System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
        } else {
            if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
                System.out.println("Linux computer name throguh env:\"" + System.getenv("HOSTNAME") + "\"");
                System.out.println("Linux computer name through exec:\"" + execReadToString("hostname") + "\"");
                System.out.println("Linux computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
            }
        }
    }

    public static String execReadToString(String execCommand) throws IOException {
        Process proc = Runtime.getRuntime().exec(execCommand);
        try (InputStream stream = proc.getInputStream()) {
            try (Scanner s = new Scanner(stream).useDelimiter("\\A")) {
                return s.hasNext() ? s.next() : "";
            }
        }
    }

Results for different operating systems:

OpenSuse 13.1

Linux computer name throguh env:"machinename"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:""

Ubuntu 14.04 LTS
This one is kinda strange since echo $HOSTNAME returns the correct hostname, but System.getenv("HOSTNAME") does not (this however might be an issue with my environment only):

Linux computer name throguh env:"null"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:"machinename
"

Windows 7

Windows computer name throguh env:"MACHINENAME"
Windows computer name through exec:"machinename
"

The machine names have been replaced for (some) anonymization, but I've kept the capitalization and structure. Note the extra newline when executing hostname, you might have to take it into account in some cases.

灵芸 2024-11-15 07:28:27

或者,使用 JNA 在 Unix 上调用 gethostname 函数,避免相反的情况DNS 查找。

一些注意事项:在 Linux 上,我相信 gethostname 只是调用 uname 并解析输出。在 OS X 上,情况更加复杂,因为您的主机名可能会受到 DNS 的影响,但除了这些副作用之外,这绝对是我从 hostname 获得的。

import com.sun.jna.LastErrorException
import com.sun.jna.Library
import com.sun.jna.Native

...

private static final C c = (C) Native.loadLibrary("c", C.class);

private static interface C extends Library {
    public int gethostname(byte[] name, int size_t) throws LastErrorException;
}

public String getHostName() {
    byte[] hostname = new byte[256];
    c.gethostname(hostname, hostname.length)
    return Native.toString(hostname)
}

jna-platform.jar 包含 Win32 函数,因此只需调用 Kernel32Util.getComputerName() 即可。

Alternatively, use JNA to call the gethostname function on unixes, avoiding the reverse DNS lookup.

Some notes: on Linux, I believe gethostname simply calls uname and parses the output. On OS X the situation is more complex, as your hostname can be affected by DNS, but those side-effects aside, it's definitely what I get from hostname.

import com.sun.jna.LastErrorException
import com.sun.jna.Library
import com.sun.jna.Native

...

private static final C c = (C) Native.loadLibrary("c", C.class);

private static interface C extends Library {
    public int gethostname(byte[] name, int size_t) throws LastErrorException;
}

public String getHostName() {
    byte[] hostname = new byte[256];
    c.gethostname(hostname, hostname.length)
    return Native.toString(hostname)
}

jna-platform.jar includes Win32 functions, so there it's as simple as a call to Kernel32Util.getComputerName().

又爬满兰若 2024-11-15 07:28:27

如果您获得 127.0.0.1 作为 IP 地址,那么您可能需要找到操作系统特定的 hosts 文件,并在其中添加到主机名的映射。

If you are getting 127.0.0.1 as the IP address then you may need to locate your Operating System specific hosts file and add a mapping to your hostname in it.

昵称有卵用 2024-11-15 07:28:27

这有点像黑客。但是您可以从 Java 启动一个新进程并运行 hostname 命令。读取子进程的输出流将为您提供本地主机的名称。

This is a bit of a hack. But you could launch a new Process from Java and run the hostname command. Reading the outputstream of the child process would give you the name of the localhost.

雪落纷纷 2024-11-15 07:28:27

如果没有配置 DNS,Java 会读取 /etc/hosts 文件,或者相应的 C 函数会读取。

Java will read the /etc/hosts file if there is no DNS configured, or rather the corresponding C functions will.

坏尐絯 2024-11-15 07:28:27

在 Linux 上阅读

/proc/sys/kernel/hostname

on Linux read

/proc/sys/kernel/hostname
怀念你的温柔 2024-11-15 07:28:27

如果您不反对使用 Maven Central 的外部依赖项,我编写了 gethostname4j 来为自己解决这个问题。它只是使用 JNA 调用 libc 的 gethostname 函数(或在 Windows 上获取 ComputerName)并将其作为字符串返回给您。

https://github.com/mattsheppard/gethostname4j

(我认为这几乎正是@danny-thomas建议,但如果您已经在使用 Maven,可能会更方便;)

If you're not against using an external dependency from maven central, I wrote gethostname4j to solve this problem for myself. It just uses JNA to call libc's gethostname function (or gets the ComputerName on Windows) and returns it to you as a string.

https://github.com/mattsheppard/gethostname4j

(I think it's almost exactly what @danny-thomas proposed, but maybe more convenient if you're already using Maven ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文