虽然这个话题已经回答了,但还有很多话要说。
首先:显然我们需要一些定义。 InetAddress.getLocalHost().getHostName() 为您提供从网络角度看的主机名称。这种方法的问题在其他答案中有很好的记录:它通常需要 DNS 查找,如果主机有多个网络接口并且有时会失败(见下文),它会很模糊。
但在任何操作系统上都有另一个名称。在启动过程中很早就定义的主机名称,早在网络初始化之前。 Windows 将其称为 computername,Linux 将其称为 kernel hostname,而 Solaris 使用单词 nodename。我最喜欢计算机名这个词,所以从现在开始我会使用这个词。
查找计算机名
Java 无法获得我定义为“计算机名”的内容。 当然,有其他答案中描述的解决方法,例如 Windows 调用 System.getenv("COMPUTERNAME"),但在 Unix/Linux 上如果不求助于 JNI/JNA 或 Runtime.exec(),就没有好的解决方法。如果您不介意 JNI/JNA 解决方案,那么 gethostname4j 非常简单且非常易于使用。
让我们继续看两个示例,一个来自 Linux,一个来自 Solaris,它们演示了如何轻松进入无法使用标准 Java 方法获取计算机名的情况。
Linux 示例
在一个新创建的系统上,安装过程中主机被命名为“chicago”,我们现在更改所谓的内核主机名:
$ hostnamectl --static set-hostname dallas
现在内核主机名是“dallas”,从 hostname 命令可以看出:
$ hostname
dallas
但我们还有
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
这里没有错误配置。这只是意味着主机的网络名称(或者更确切地说是环回接口的名称)与主机的计算机名不同。
现在,尝试执行InetAddress.getLocalHost().getHostName(),它会抛出 java.net.UnknownHostException。你基本上被卡住了。无法检索值 'dallas' 和值 'chicago'。
Solaris 示例
以下示例基于 Solaris 11.3。
故意配置了主机,以便环回名称节点名。
换句话说,我们有:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
和 /etc/hosts 的内容:
:1 chicago localhost
127.0.0.1 chicago localhost loghost
hostname 命令的结果是:
$ hostname
dallas
就像在 Linux 示例中一样,对 InetAddress.getLocalHost().getHostName() 的调用将失败并显示
java.net.UnknownHostException: dallas: dallas: node name or service name not known
就像你现在卡住的 Linux 示例一样。无法检索值 'dallas' 和值 'chicago'。
你什么时候才能真正解决这个问题?
您经常会发现InetAddress.getLocalHost().getHostName() 确实会返回一个等于计算机名的值。所以没有问题(除了名称解析的额外开销)。
问题通常出现在 PaaS 环境中,其中计算机名和环回接口的名称之间存在差异。例如,人们报告 Amazon EC2 中的问题。
错误/RFE 报告
稍作搜索发现此 RFE 报告:link1、link2。但是,从该报告中的 cmets 来看,JDK 团队似乎在很大程度上误解了该问题,因此不太可能得到解决。
我喜欢 RFE 与其他编程语言的比较。