建议在Java中获取主机名的方法

问题

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

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

VS
InetAddress.getLocalHost().getHostName()


#1 热门回答(289 赞)

严格来说 - 你别无选择,只能在Unixgethostname(2)上调用hostname(1)或者。这是你的计算机的名称。任何通过IP地址确定主机名的尝试都是这样的

InetAddress.getLocalHost().getHostName()

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

  • IP地址可能无法解析为任何名称。错误的DNS设置,糟糕的系统设置或错误的提供商设置可能是这个原因。
  • DNS中的名称可以有许多名为CNAME的别名。这些只能在一个方向上正确解决:名称到地址。反方向是模棱两可的。哪一个是"官方"名称?
  • 主机可以有许多不同的IP地址 - 每个地址可以有许多不同的名称。两种常见情况是:一个以太网端口有几个"逻辑"IP地址,或者计算机有几个以太网端口。它是可配置的,无论它们共享IP还是具有不同的IP。这被称为"多宿主"。
  • DNS中的一个名称可以解析为多个IP地址。并非所有这些地址都必须位于同一台计算机上! (用例:一种简单的负载均衡形式)
  • 我们甚至不开始讨论动态IP地址。

另外,请勿将IP地址的名称与主机名(主机名)混淆。一个比喻可能会让它更清晰:

有一个叫做"伦敦"的大城市(服务器)。在城墙里面发生了很多事情。这个城市有几个门(IP地址)。每个门都有一个名称("北门","河门","南安普顿门"......),但门的名称不是城市的名称。此外,你不能通过使用门的名称来推断城市的名称 - "北门"将捕获一半的大城市,而不只是一个城市。然而 - 一个陌生人(IP包)沿着河边走来问当地人:"我有一个奇怪的地址:'Rivergate,第二个左边,第三个房子'。你能帮助我吗?"当地人说:"当然,你走在正确的道路上,只需前进,你将在半小时内抵达目的地。"

这说明了我的想法。

好消息是:Therealhostname通常不是必需的。在大多数情况下,任何解析为此主机上的IP地址的名称都可以。 (陌生人可能会通过Northgate进入城市,但乐于助人的当地人会翻译"左二"部分。)

如果剩下的极端情况,你必须使用此配置设置的确定源 - 这是C函数gethostname(2)。该函数也由programhostname调用。


#2 热门回答(86 赞)

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

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

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

  • Java当前计算机名称并登录用户?
  • 获取远程计算机看到的本地计算机的DNS名称

**编辑:**你应该查看A.H.'s answerArnout Engelen's answer,详细了解为什么这可能无法按预期工作,具体取决于你的具体情况。作为这个特别要求携带的人的答案,我仍然认为很好,但他们提出了一些应该考虑的好点。


#3 热门回答(32 赞)

正如其他人所说,根据DNS解析获取主机名是不可靠的。

由于遗憾的是这个问题仍然存在于2018,我想与你分享我的网络独立解决方案,并在不同系统上进行一些测试。

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

  • 在Windows上通过System.getenv()读取COMPUTERNAME环境变量。执行hostname.exe并读取响应
  • 在Linux上通过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() : "";
    }
}

不同操作系统的结果:
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:""

OpenSuse 13.1

Unix-like computer name through env:"machinename"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""

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
"

**编辑:**如果你在执行Java代码之前运行export HOSTNAME,则根据legolas108,System.getenv("HOSTNAME")在Ubuntu 14.04上运行。
Windows 7

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

Windows 10

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

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