Mah*_*dra 262 java network-programming hostname environment-variables
以下哪项是获取Java当前计算机主机名的最佳和最便携方式?
Runtime.getRuntime().exec("hostname")
VS
InetAddress.getLocalHost().getHostName()
A.H*_*.H. 326
严格来说 - 除了hostname(1)在Unix上调用之外你别无选择gethostname(2).这是您的计算机的名称.任何通过IP地址确定主机名的尝试都是这样的
InetAddress.getLocalHost().getHostName()
Run Code Online (Sandbox Code Playgroud)
在某些情况下必然会失败:
另外,请勿将IP地址的名称与主机名(主机名)混淆.一个比喻可能会让它更清晰:
有一个叫做"伦敦"的大城市(服务器).城墙内部发生了很多事情.这个城市有几个门(IP地址).每个门都有一个名字("北门","河门","南安普顿门"......),但门的名称不是城市的名称.此外,你不能通过使用门的名称来推断城市的名称 - "北门"将捕获一半的大城市,而不只是一个城市.然而 - 一个陌生人(IP包)沿着河边走来问当地人:"我有一个奇怪的地址:'Rivergate,第二个左边,第三个房子'.你能帮助我吗?" 当地人说:"当然,你走在正确的道路上,只需前进,你将在半小时内到达目的地."
这说明了我的想法.
好消息是:真正的主机名通常不是必需的.在大多数情况下,任何解析为此主机上的IP地址的名称都可以.(陌生人可能会通过Northgate进入城市,但乐于助人的当地人会翻译"左二"部分.)
如果剩下的角落情况,您必须使用此配置设置的权威来源 - 这是C函数gethostname(2).该功能也由程序调用hostname.
Nic*_*son 91
InetAddress.getLocalHost().getHostName() 是更便携的方式.
exec("hostname")实际上调用操作系统来执行hostname命令.
以下是关于SO的其他几个相关答案:
编辑:您应该看看AH的答案或Arnout Engelen的答案,详细说明为什么这可能无法按预期工作,具体取决于您的情况.作为这个特别要求携带的人的答案,我仍然觉得getHostName()很好,但是他们提出了一些应该考虑的好点.
Mal*_*alt 51
正如其他人所说,根据DNS解析获取主机名是不可靠的.
由于遗憾的是这个问题在2018年仍然存在,我想与您分享我的网络独立解决方案,并在不同系统上进行一些测试.
以下代码尝试执行以下操作:
在Windows上
COMPUTERNAME通过读取环境变量System.getenv().
执行hostname.exe并阅读响应
在Linux上
HOSTNAME通过读取环境变量System.getenv()
执行hostname并阅读响应
读取/etc/hostname(为此我正在执行,cat因为代码片段已经包含执行和读取的代码.但是,阅读文件会更好).
代码:
public static void main(String[] args) throws IOException {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
System.out.println("Windows computer name through env:\"" + System.getenv("COMPUTERNAME") + "\"");
System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
} else if (os.contains("nix") || os.contains("nux") || os.contains("mac os x")) {
System.out.println("Unix-like computer name through env:\"" + System.getenv("HOSTNAME") + "\"");
System.out.println("Unix-like computer name through exec:\"" + execReadToString("hostname") + "\"");
System.out.println("Unix-like computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
}
}
public static String execReadToString(String execCommand) throws IOException {
try (Scanner s = new Scanner(Runtime.getRuntime().exec(execCommand).getInputStream()).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}
Run Code Online (Sandbox Code Playgroud)
不同操作系统的结果:
macOS 10.13.2
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
Run Code Online (Sandbox Code Playgroud)
OpenSuse 13.1
Unix-like computer name through env:"machinename"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""
Run Code Online (Sandbox Code Playgroud)
Ubuntu 14.04 LTS
这个有点奇怪,因为echo $HOSTNAME返回正确的主机名,但System.getenv("HOSTNAME")不是:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
Run Code Online (Sandbox Code Playgroud)
编辑:根据legolas108,System.getenv("HOSTNAME")如果你运行,可以在Ubuntu 14.04上运行export HOSTNAME在执行Java代码之前.
Windows 7的
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
Run Code Online (Sandbox Code Playgroud)
Windows 10
Windows computer name through env:"MACHINENAME"
Windows computer name through exec:"machinename
"
Run Code Online (Sandbox Code Playgroud)
机器名称已被替换,但我保留了大写和结构.请注意执行时的额外换行符hostname,在某些情况下可能需要考虑它.
Arn*_*len 23
InetAddress.getLocalHost().getHostName() 更好(正如尼克所解释的那样),但仍然不是很好
一个主机可以在许多不同的主机名下知道.通常,您将在特定的上下文中查找主机所具有的主机名.
例如,在Web应用程序中,您可能正在查找发出您当前正在处理的请求的人使用的主机名.如何最好地找到一个取决于您用于Web应用程序的框架.
在某些其他面向互联网的服务中,您需要通过"外部"提供您的服务的主机名.由于代理,防火墙等,这甚至可能不是您的服务所安装的计算机上的主机名 - 您可能会尝试提供合理的默认设置,但您绝对应该为安装此设备的人配置此设置.
pet*_*erh 14
虽然已经回答了这个话题,但还有更多话要说.
首先:显然我们需要一些定义.从网络角度看,它InetAddress.getLocalHost().getHostName()为您提供了主机的名称.这种方法的问题在其他答案中得到了很好的记录:它通常需要DNS查找,如果主机有多个网络接口,它有点模糊,有时候很明显失败(见下文).
但在任何操作系统上都有另一个名称.在网络初始化之前很久就在引导过程的早期定义的主机的名称.Windows将其称为计算机名称,Linux将其称为内核主机名,Solaris使用单词nodename.我最喜欢computername这个词,所以从现在开始我会用这个词.
在Linux/Unix上,计算机名是从C函数获得的gethostname(),或者是hostname来自shell或HOSTNAME环境变量的命令,类似于Bash的shell.
在Windows上,computername是您从环境变量COMPUTERNAME或Win32 GetComputerName函数获得的.
Java无法获得我所定义的'computername'.当然,还有其他答案中描述的解决方法,比如Windows调用System.getenv("COMPUTERNAME"),但在Unix/Linux上,如果不诉诸JNI/JNA或者没有好的解决方法Runtime.exec().如果您不介意JNI/JNA解决方案,那么gethostname4j很简单且非常容易使用.
让我们继续两个例子,一个来自Linux,另一个来自Solaris,它们演示了如何使用标准Java方法无法获得计算机名的情况.
在新创建的系统中,安装期间的主机被命名为"chicago",我们现在更改所谓的内核主机名:
$ hostnamectl --static set-hostname dallas
Run Code Online (Sandbox Code Playgroud)
现在内核主机名是'dallas',从hostname命令可以看出:
$ hostname
dallas
Run Code Online (Sandbox Code Playgroud)
但我们还有
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
Run Code Online (Sandbox Code Playgroud)
这没有错误的配置.它只是意味着主机的网络名称(或者更确切地说是环回接口的名称)与主机的计算机名称不同.
现在,尝试执行InetAddress.getLocalHost().getHostName() ,它将抛出java.net.UnknownHostException.你基本上卡住了.没有办法既不检索'dallas'值也不检索'chicago'值.
以下示例基于Solaris 11.3.
故意配置主机,以便环回名称<>节点名称.
换句话说,我们有:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
Run Code Online (Sandbox Code Playgroud)
和/ etc/hosts的内容:
:1 chicago localhost
127.0.0.1 chicago localhost loghost
Run Code Online (Sandbox Code Playgroud)
并且hostname命令的结果将是:
$ hostname
dallas
Run Code Online (Sandbox Code Playgroud)
就像在Linux示例中一样,调用InetAddress.getLocalHost().getHostName()将失败
java.net.UnknownHostException: dallas: dallas: node name or service name not known
Run Code Online (Sandbox Code Playgroud)
就像Linux的例子一样,你现在卡住了.没有办法既不检索'dallas'值也不检索'chicago'值.
通常你会发现它InetAddress.getLocalHost().getHostName()确实会返回一个等于计算机名的值.所以没有问题(除了名称解析的额外开销).
问题通常发生在PaaS环境中,其中computername和loopback接口的名称之间存在差异.例如,人们报告Amazon EC2中的问题.
一些搜索揭示了这个RFE报告:link1,link2.但是,从对该报告的评论来看,这个问题似乎在很大程度上被JDK团队误解了,因此不太可能解决.
我喜欢RFE与其他编程语言的比较.
Tho*_*s W 11
环境变量也可以提供一种有用的方法 - COMPUTERNAME在Windows上,HOSTNAME在大多数现代Unix/Linux shell上.
请参阅:https: //stackoverflow.com/a/17956000/768795
我正在使用这些作为"补充"方法InetAddress.getLocalHost().getHostName(),因为有几个人指出,该功能在所有环境中都不起作用.
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;
Run Code Online (Sandbox Code Playgroud)
只是单行......跨平台(Windows-Linux-Unix-Mac(Unix))[总是有效,不需要DNS]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
Run Code Online (Sandbox Code Playgroud)
你完成了 !!
在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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果你不反对使用 maven central 的外部依赖,我写了 gethostname4j 来为自己解决这个问题。它只是使用 JNA 调用 libc 的 gethostname 函数(或在 Windows 上获取 ComputerName)并将其作为字符串返回给您。
https://github.com/mattsheppard/gethostname4j
| 归档时间: |
|
| 查看次数: |
311479 次 |
| 最近记录: |