推荐使用Java来获取主机名

以下哪个是用Java获取当前计算机主机名的最好的和最便携的方法?

Runtime.getRuntime().exec("hostname")

VS

InetAddress.getLocalHost().getHostName()

严格地说 – 你别无select,只能在Unix gethostname(2)上调用hostname(1)或 – 。 这是你电脑的名字。 任何尝试通过像这样的IP地址来确定主机名

 InetAddress.getLocalHost().getHostName() 

在某些情况下必然会失败:

  • IP地址可能不会parsing为任何名称。 错误的DNS设置,错误的系统设置或错误的提供程序设置可能是原因。
  • DNS中的名称可以有多个名为CNAME的别名。 这些只能在一个方向上正确解决:名称到地址。 相反的方向是不明确的。 哪一个是“官方”的名字?
  • 主机可以有许多不同的IP地址 – 每个地址可以有许多不同的名称。 两种常见的情况是:一个以太网端口有几个“逻辑”IP地址,或者计算机有几个以太网端口。 它们是共享一个IP还是具有不同的IP是可configuration的。 这被称为“多宿主”。
  • DNS中的一个名称可以parsing为多个IP地址。 并不是所有这些地址必须位于同一台计算机上! (Usecase:一种简单的负载平衡forms)
  • 我们甚至不开始谈论dynamicIP地址。

也不要混淆IP地址的名称与主机名(主机名)。 比喻可能会更清楚:

有一个叫“伦敦”的大城市(服务器)。 在城墙里面发生了很多事情。 这个城市有几个大门(IP地址)。 每个门都有一个名称(“北门”,“河门”,“南安普顿门”),但门的名称不是城市的名称。 你也不能用门的名字来推断城市的名字 – “北门”将会覆盖大城市的一半,而不只是一个城市。 然而,一个陌生人(IP包)在河边散步,问一个地方:“我有一个奇怪的地址:”Rivergate,第二个左边,第三个房子“,你能帮我吗? 当地人说:“当然,你走在正确的道路上,只要继续前进,你将在半小时内抵达目的地。”

这说明了我的想法。

好消息是: 真正的主机名通常不是必需的。 在大多数情况下,在这个主机上parsing成IP地址的任何名字都可以。 (陌生人可以通过诺斯盖特进入城市,但有用的当地人翻译“左二”部分。)

如果剩余的angular落案例必须使用此configuration设置的明确来源 – 这是C函数gethostname(2) 。 该function也被程序hostname调用。

InetAddress.getLocalHost().getHostName()是更便携的方式。

exec("hostname")实际调用到操作系统执行hostname命令。

以下是关于SO的其他相关答案:

  • Java当前的机器名称和login用户?
  • 获取远程计算机所看到的本地计算机的DNS名称

编辑:你应该看看AH的答案或Arnout Engelen的答案 ,为什么这可能无法按预期工作的细节取决于你的情况。 作为专门请求便携式应用程序的人的答案,我仍然认为getHostName()是好的,但是他们提出了一些应该考虑的优点。

正如其他人已经指出,获取基于DNSparsing的主机名是不可靠的。

由于这个问题在2016年不幸仍然相关,我想与您分享我的networking独立解决scheme,并在不同的系统上运行一些testing。

以下代码尝试执行以下操作:

  • 在Windows上

    1. 通过System.getenv()读取COMPUTERNAME环境variables。

    2. 执行hostname.exe并读取响应

  • 在Linux上

    1. 通过System.getenv()读取HOSTNAME环境variables

    2. 执行hostname并读取响应

    3. 阅读/etc/hostname (这样做我正在执行cat因为代码片段已经包含执行和读取代码,只是读取文件会更好,虽然)。

代码:

 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 through env:"null" Linux computer name through exec:"machinename " Linux computer name through /etc/hostname:"machinename " 

编辑:根据legolas108 ,如果您在执行Java代码之前运行export HOSTNAMESystem.getenv("HOSTNAME")在Ubuntu 14.04上工作。

Windows 7的

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

机器名已被replace,但我保留了大小写和结构。 在执行hostname时请注意额外的换行符,在某些情况下可能需要考虑它。

InetAddress.getLocalHost().getHostName()更好(正如Nick所解释的),但是还不是很好

一台主机可以在许多不同的主机名下被知道。 通常你会寻找你的主机在特定环境下的主机名。

例如,在一个Web应用程序中,您可能正在查找发出您当前正在处理的请求的人使用的主机名。 如何最好地发现一个取决于你的Web应用程序使用哪个框架。

在某种其他面向互联网的服务中,您需要从“外部”获取您的服务的主机名。 由于代理,防火墙等,这可能甚至不是你的服务安装在机器上的主机名 – 你可能会试图想出一个合理的默认值,但是你应该明确地设置这个安装这个的人。

环境variables也可以提供有用的方法 – Windows上的COMPUTERNAME ,大多数现代Unix / Linux shell上的HOSTNAME

请参阅: https : //stackoverflow.com/a/17956000/768795

我正在使用这些作为“补充”的方法InetAddress.getLocalHost().getHostName() ,因为有几个人指出,该function不适用于所有环境。

Runtime.getRuntime().exec("hostname")是另一个可能的补充。 在这个阶段,我没有用过它。

 import java.net.InetAddress; import java.net.UnknownHostException; // try InetAddress.LocalHost first; // NOTE -- InetAddress.getLocalHost().getHostName() will not work in certain environments. try { String result = InetAddress.getLocalHost().getHostName(); if (StringUtils.isNotEmpty( result)) return result; } catch (UnknownHostException e) { // failed; try alternate means. } // try environment properties. // String host = System.getenv("COMPUTERNAME"); if (host != null) return host; host = System.getenv("HOSTNAME"); if (host != null) return host; // undetermined. return null; 

使用Java获取当前计算机主机名的最便捷方式如下:

 import java.net.InetAddress; import java.net.UnknownHostException; public class getHostName { public static void main(String[] args) throws UnknownHostException { InetAddress iAddress = InetAddress.getLocalHost(); String hostName = iAddress.getHostName(); //To get the Canonical host name String canonicalHostName = iAddress.getCanonicalHostName(); System.out.println("HostName:" + hostName); System.out.println("Canonical Host Name:" + canonicalHostName); } } 
 hostName == null; Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); { while (interfaces.hasMoreElements()) { NetworkInterface nic = interfaces.nextElement(); Enumeration<InetAddress> addresses = nic.getInetAddresses(); while (hostName == null && addresses.hasMoreElements()) { InetAddress address = addresses.nextElement(); if (!address.isLoopbackAddress()) { hostName = address.getHostName(); } } } } 

虽然这个话题已经被回答了,但还有更多要说的。

首先:显然我们在这里需要一些定义。 InetAddress.getLocalHost().getHostName()为您提供从networkingangular度看的主机名称。 其他答案详细logging了这种方法的问题:它通常需要DNS查找,如果主机有多个networking接口,并且有时会失败,请参阅下文。

但是在任何操作系统上都有另一个名字。 早在networking初始化之前,在启动过程中很早定义的主机名称。 Windows将其称为computername ,Linux将其称为内核主机名,而Solaris使用nodename这个词。 我最喜欢computername这个词,所以我从现在开始用这个词。

findcomputername

  • 在Linux / Unix上,计算机名是从C函数gethostname()或shell或HOSTNAME环境variables的Bash-like shell中的hostname命令获得的。

  • 在Windows上,计算机名称是从环境variablesCOMPUTERNAME或Win32 GetComputerName函数获得的。

Java没有办法获得我所定义的“计算机名”。 当然,还有其他答案中描述的解决方法,比如Windows调用System.getenv("COMPUTERNAME") ,但是在Unix / Linux上,没有使用JNI / JNA或Runtime.exec()就没有好的解决方法。 如果你不介意JNI / JNA的解决scheme,那么gethostname4j是死的简单,很容易使用。

让我们继续讲两个例子,一个来自Linux,另一个来自Solaris,它演示了如何使用标准Java方法轻松地获取计算机名。

Linux例子

在新创build的系统上,安装过程中的主机被命名为'chicago',现在我们改变所谓的内核主机名:

 $ hostnamectl --static set-hostname dallas 

现在内核的主机名是'dallas',如hostname命令所示:

 $ hostname dallas 

但我们仍然有

 $ cat /etc/hosts 127.0.0.1 localhost 127.0.0.1 chicago 

这里没有configuration错误。 这只是意味着主机的networking名称(或更确切地说,是回送接口的名称)与主机的计算机名称不同。

现在,尝试执行InetAddress.getLocalHost().getHostName() ,它将抛出java.net.UnknownHostException。 你基本卡住了。 无法检索“达拉斯”的价值和“芝加哥”的价值。

Solaris示例

以下示例基于Solaris 11.3。

主机已经故意configuration,使得回环名称<> nodename。

换句话说,我们有:

 $ 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例子一样,你现在被卡住了。 无法检索“达拉斯”的价值和“芝加哥”的价值。

你什么时候真的会为此而挣扎?

很多时候你会发现InetAddress.getLocalHost().getHostName()的确会返回一个和computername相等的值。 所以没有问题(除了名称parsing的额外开销)。

问题出现在PaaS环境中,在computername和loopback接口的名称之间有区别。 例如,人们在Amazon EC2中报告问题。

Bug / RFE报告

一些search显示这个RFE报告: link1 , link2 。 然而,从对该报告的评论来看,JDK团队似乎已经在很大程度上误解了这个问题,所以不太可能解决这个问题。

我喜欢RFE与其他编程语言的比较。

如果你不反对从Maven中心使用外部依赖,我写了gethostname4j来解决这个问题。 它只是使用JNA调用libc的gethostname函数(或者在Windows上获取ComputerName)并将其作为string返回给您。

https://github.com/mattsheppard/gethostname4j

InetAddress.getLocalHost()。getHostName()是两者中最好的方法,因为这是开发人员级别上最好的抽象。