次のうちどれがJavaで現在のコンピュータのホスト名を取得するための最善かつ最も移植性の高い方法ですか?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
厳密に言えば - あなたはhostname(1)
か - Unixのgethostname(2)
のどちらかを呼ぶ以外に選択肢はありません。これはあなたのコンピュータの名前です。このようなIPアドレスでホスト名を特定しようとする試み
InetAddress.getLocalHost().getHostName()
状況によっては失敗するはずです。
IPアドレスの名前とホストの名前(ホスト名)を混同しないでください。比喩はそれをより明確にするかもしれません:
"London"という大都市(サーバー)があります。街の壁の内側にはたくさんの商売があります。市にはいくつかのゲート(IPアドレス)があります。各門には名前( "North Gate"、 "River Gate"、 "Southampton Gate"など)がありますが、門の名前は市の名前ではありません。また、門の名前を使用して都市の名前を推測することはできません - "North Gate"は、1つの都市だけでなく、より大きな都市の半分を占めることになります。しかし - 見知らぬ人(IPパケット)が川に沿って歩き、地元の人に尋ねました。「私は奇妙な住所を持っています。地元の人によると、「もちろん、あなたは正しい道を進んでいます。ただ先に進むと、30分以内に目的地に到着します。」
これは私が思うにそれをかなり説明しています。
良いニュースは次のとおりです。実際のホスト名は通常は不要です。ほとんどの場合、このホストのIPアドレスに解決される名前であれば問題ありません。 (見知らぬ人がノースゲートで街に入るかもしれませんが、親切な地元の人々が「左から2番目」の部分を翻訳しています。)
残りのコーナーの場合は、この構成設定の最も信頼性の高いソースを使用する必要があります。これがC関数のgethostname(2)
です。その関数はプログラムhostname
によっても呼び出されます。
InetAddress.getLocalHost().getHostName()
はより移植性の高い方法です。
exec("hostname")
は、実際にはオペレーティングシステムを呼び出してhostname
コマンドを実行します。
これがSOに関する他の2つの関連する答えです。
編集:詳しくは AHの答え または Arnout Engelenの答え をご覧ください。あなたの状況によってはなぜこれが期待通りに動かないかもしれないかについて。特にポータブルを要求したこの人のための答えとして、私はまだgetHostName()
が良いと思います、しかし彼らは考慮されるべきであるいくつかの良い点を思い出させます。
他の人が指摘したように、DNS解決に基づいてホスト名を取得することは信頼できません。
残念ながらこの質問は 2018 に関連しているので、私はあなたと私のネットワークに依存しないソリューションを共有したいと思います。いくつかのテストを異なるシステムで実行します。
次のコードは、次のことを試みます。
Windowsの場合
System.getenv()
を通してCOMPUTERNAME
環境変数を読みます。
hostname.exe
を実行してレスポンスを読む
Linuxの場合
System.getenv()
を通してHOSTNAME
環境変数を読みます
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
"
編集:legolas108 によると、Javaコードを実行する前にexport HOSTNAME
を実行すると、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
を実行するときの余分な改行に注意してください、場合によってはそれを考慮に入れなければならないかもしれません。
InetAddress.getLocalHost().getHostName()
は(Nickによって説明されているように)優れていますが、まだそれほど良くはありません
1つのホストは、さまざまなホスト名で識別できます。通常、あなたのホストが特定のコンテキストで持っているホスト名を探します。
たとえば、Webアプリケーションでは、現在処理している要求を発行した人が誰でも使用しているホスト名を探しているかもしれません。それを最もよく見つける方法は、Webアプリケーションにどのフレームワークを使用しているかによって異なります。
他のインターネット向けサービスでは、あなたのサービスが利用可能なホスト名を 'outside'から利用できるようにしたいでしょう。プロキシ、ファイアウォールなどのために、これはあなたのサービスがインストールされているマシン上のホスト名でさえないかもしれません - あなたは合理的なデフォルトを考え出そうと試みるかもしれません。
このトピックはすでに回答されていますが、言うべきことがもっとあります。
まず第一に:ここでは明らかにいくつかの定義が必要です。 InetAddress.getLocalHost().getHostName()
は、ネットワークの観点から見たホストの名前を示します。このアプローチの問題は他の答えでよく文書化されています:それはしばしばDNSルックアップを必要とします、ホストが複数のネットワークインターフェースを持っているならそれはあいまいです、そしてそれは時々明白に失敗します(下記参照)。
しかし、どのOSでも別の名前があります。ネットワークが初期化されるずっと前のブートプロセスの非常に早い段階で定義されるホストの名前。 Windowsはこれをコンピュータ名と呼び、Linuxはそれをカーネルホスト名と呼び、SolarisはWordノード名を使います。私はWordコンピュータ名が一番好きなので、これからWordを使います。
Linux/Unixでは、コンピュータ名は、Cの関数gethostname()
、またはShellのhostname
コマンド、またはBash風シェルのHOSTNAME
環境変数から取得したものです。
Windowsでは、コンピュータ名は、環境変数COMPUTERNAME
またはWin32のGetComputerName
関数から取得したものです。
Javaには 'computername'として定義したものを取得する方法がありません。確かに、WindowsがSystem.getenv("COMPUTERNAME")
を呼び出すような他の答えで説明されているような回避策はありますが、Unix/Linuxではありません。 JNI/JNAやRuntime.exec()
に頼らずに良い回避策。あなたがJNI/JNAの解決策を気にしないのであれば、 gethostname4j があり、とても単純で使いやすいです。
LinuxとSolarisの2つの例を見てみましょう。これらは、標準のJavaメソッドを使用してコンピューター名を取得できない状況に簡単に入る方法を示しています。
インストール中のホストが 'chicago'と命名された、新しく作成されたシステムでは、いわゆるカーネルホスト名を変更します。
$ hostnamectl --static set-hostname dallas
Hostnameコマンドから明らかなように、カーネルのホスト名は 'dallas'です。
$ hostname
dallas
しかし、我々はまだ持っています
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
これには誤設定はありません。それは単にホストのネットワーク名(あるいはループバックインターフェースの名前)がホストのコンピュータ名と異なることを意味します。
さて、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
そして/ 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()
が実際にcomputernameと等しい値を返すことがよくあります。それで問題はありません(名前解決の追加されたオーバーヘッドを除いて)。
この問題は通常、computernameとloopbackインタフェースの名前に違いがあるPaaS環境で発生します。例えば、人々はAmazon EC2の問題を報告しています。
少し検索すると、このRFEレポートが明らかになります。 link1 、 link2 。ただし、そのレポートに対するコメントから判断すると、この問題はJDKチームによって大きく誤解されているように思われるため、対処される可能性は低いです。
私はRFEと他のプログラミング言語との比較が好きです。
環境変数も有用な手段を提供するかもしれません - WindowsではCOMPUTERNAME
、最近のほとんどのUnix/LinuxシェルではHOSTNAME
。
参照してください: 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;
現在のコンピュータのホスト名を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();
}
}
}
}
あなたがMaven Centralからの外部依存関係を使用することに反対でないならば、私は私自身のためにこの問題を解決するためにgethostname4jを書きました。 JNAを使用してlibcのgethostname関数を呼び出し(またはWindowsではComputerNameを取得し)、それを文字列として返します。