推荐使用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上
-
通过
System.getenv()
读取COMPUTERNAME
环境variables。 -
执行
hostname.exe
并读取响应
-
-
在Linux上
-
通过
System.getenv()
读取HOSTNAME
环境variables -
执行
hostname
并读取响应 -
阅读
/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 HOSTNAME
, System.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上,计算机名称是从环境variables
COMPUTERNAME
或Win32GetComputerName
函数获得的。
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返回给您。
InetAddress.getLocalHost()。getHostName()是两者中最好的方法,因为这是开发人员级别上最好的抽象。