Welche der folgenden Methoden ist die beste und portabelste Methode, um den Hostnamen des aktuellen Computers in Java abzurufen?
Runtime.getRuntime().exec("hostname")
vs.
InetAddress.getLocalHost().getHostName()
Welche der folgenden Methoden ist die beste und portabelste Methode, um den Hostnamen des aktuellen Computers in Java abzurufen?
Runtime.getRuntime().exec("hostname")
vs.
InetAddress.getLocalHost().getHostName()
Antworten:
Genau genommen haben Sie keine andere Wahl, als entweder hostname(1)
oder unter Unix anzurufen gethostname(2)
. Dies ist der Name Ihres Computers. Jeder Versuch, den Hostnamen anhand einer solchen IP-Adresse zu ermitteln
InetAddress.getLocalHost().getHostName()
ist unter bestimmten Umständen zum Scheitern verurteilt:
Verwechseln Sie auch nicht den Namen einer IP-Adresse mit dem Namen des Hosts (Hostname). Eine Metapher könnte es klarer machen:
Es gibt eine große Stadt (Server) namens "London". Innerhalb der Stadtmauern passiert viel Geschäft. Die Stadt hat mehrere Tore (IP-Adressen). Jedes Tor hat einen Namen ("North Gate", "River Gate", "Southampton Gate" ...), aber der Name des Tors ist nicht der Name der Stadt. Sie können den Namen der Stadt auch nicht mit dem Namen eines Tors ableiten - "Nordtor" würde die Hälfte der größeren Städte und nicht nur eine Stadt erfassen. Ein Fremder (IP-Paket) geht den Fluss entlang und fragt einen Einheimischen: "Ich habe eine seltsame Adresse: 'Rivergate, zweites linkes, drittes Haus'. Können Sie mir helfen?" Der Einheimische sagt: "Natürlich sind Sie auf dem richtigen Weg, fahren Sie einfach fort und Sie werden innerhalb einer halben Stunde an Ihrem Ziel ankommen."
Das zeigt es ziemlich genau, denke ich.
Die gute Nachricht ist: Der echte Hostname ist normalerweise nicht erforderlich. In den meisten Fällen reicht jeder Name aus, der in eine IP-Adresse auf diesem Host aufgelöst wird. (Der Fremde könnte die Stadt über Northgate betreten, aber hilfreiche Einheimische übersetzen den Teil "2. links".)
In den verbleibenden Eckfällen müssen Sie die endgültige Quelle dieser Konfigurationseinstellung verwenden - dies ist die C-Funktion gethostname(2)
. Diese Funktion wird auch vom Programm aufgerufen hostname
.
InetAddress.getLocalHost().getHostName()
ist der tragbarere Weg.
exec("hostname")
ruft tatsächlich das Betriebssystem auf, um den hostname
Befehl auszuführen .
Hier sind einige andere verwandte Antworten auf SO:
BEARBEITEN: Sie sollten sich die Antwort von AH oder Arnout Engelen ansehen , um zu erfahren, warum dies je nach Ihrer Situation möglicherweise nicht wie erwartet funktioniert. Als Antwort für diese Person, die speziell tragbare Geräte angefordert hat, denke ich immer noch, dass dies getHostName()
in Ordnung ist, aber sie bringt einige gute Punkte vor, die berücksichtigt werden sollten.
InetAddress.getLocalHost()
in einigen Fällen gibt den Loopback - Device. In diesem Fall wird getHostName()
"localhost" zurückgegeben, was nicht sehr nützlich ist.
Wie andere angemerkt haben, ist es unzuverlässig, den Hostnamen basierend auf der DNS-Auflösung zu erhalten.
Da diese Frage 2018 leider immer noch relevant ist , möchte ich Ihnen meine netzwerkunabhängige Lösung mit einigen Testläufen auf verschiedenen Systemen vorstellen.
Der folgende Code versucht Folgendes zu tun:
Unter Windows
Lesen Sie die COMPUTERNAME
Umgebungsvariable durch System.getenv()
.
Führen hostname.exe
Sie die Antwort aus und lesen Sie sie
Unter Linux
Lesen Sie die HOSTNAME
Umgebungsvariable durchSystem.getenv()
Führen hostname
Sie die Antwort aus und lesen Sie sie
Lesen /etc/hostname
(dazu führe ich aus, cat
da das Snippet bereits Code zum Ausführen und Lesen enthält. Es wäre jedoch besser, die Datei einfach zu lesen).
Der Code:
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() : "";
}
}
Ergebnisse für verschiedene Betriebssysteme:
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
Dieser ist etwas seltsam, da er echo $HOSTNAME
den richtigen Hostnamen zurückgibt, aber System.getenv("HOSTNAME")
nicht:
Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"
EDIT: Nach legolas108 , System.getenv("HOSTNAME")
arbeitet auf Ubuntu 14.04 , wenn Sie ausführen , export HOSTNAME
bevor Sie den Java - Code ausgeführt wird .
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
"
Die Maschinennamen wurden ersetzt, aber ich habe die Groß- und Kleinschreibung und Struktur beibehalten. Beachten Sie den zusätzlichen Zeilenumbruch bei der Ausführung. hostname
In einigen Fällen müssen Sie ihn möglicherweise berücksichtigen.
export HOSTNAME
den Java-Code vor dem Ausführen unter Ubuntu 14.04 LTS ausführen, wird er auch von zurückgegeben System.getenv("HOSTNAME")
.
export HOSTNAME
für Java verwenden, um es zu verwenden? Ich dachte, es sollte eine Standard-Umgebung wie PATH sein.
\A
Trennzeichen ist nur ein Hack zum Lesen des gesamten InputStream mit a Scanner
.
InetAddress.getLocalHost().getHostName()
ist besser (wie von Nick erklärt), aber immer noch nicht sehr gut
Ein Host kann unter vielen verschiedenen Hostnamen bekannt sein. Normalerweise suchen Sie nach dem Hostnamen, den Ihr Host in einem bestimmten Kontext hat.
In einer Webanwendung suchen Sie möglicherweise nach dem Hostnamen, der von demjenigen verwendet wird, der die Anforderung ausgegeben hat, die Sie gerade bearbeiten. Wie Sie dieses am besten finden, hängt davon ab, welches Framework Sie für Ihre Webanwendung verwenden.
Bei einer anderen Internetverbindung möchten Sie, dass der Hostname, über den Ihr Dienst verfügbar ist, von außen verfügbar ist. Aufgrund von Proxys, Firewalls usw. ist dies möglicherweise nicht einmal ein Hostname auf dem Computer, auf dem Ihr Dienst installiert ist. Sie könnten versuchen, einen vernünftigen Standard festzulegen, aber Sie sollten diesen auf jeden Fall für jeden konfigurierbar machen, der diesen installiert.
Obwohl dieses Thema bereits beantwortet wurde, gibt es noch mehr zu sagen.
Zuallererst: Natürlich brauchen wir hier einige Definitionen. Das InetAddress.getLocalHost().getHostName()
gibt Ihnen den Namen des Hosts aus der Netzwerkperspektive . Die Probleme mit diesem Ansatz sind in den anderen Antworten gut dokumentiert: Oft ist eine DNS-Suche erforderlich, es ist nicht eindeutig, ob der Host über mehrere Netzwerkschnittstellen verfügt, und manchmal schlägt dies einfach fehl (siehe unten).
Aber auf jedem Betriebssystem gibt es auch einen anderen Namen. Ein Name des Hosts, der sehr früh im Startvorgang definiert wird, lange bevor das Netzwerk initialisiert wird. Windows bezeichnet dies als Computernamen , Linux nennt es Kernel-Hostname und Solaris verwendet das Wort Knotenname . Das Wort Computername gefällt mir am besten , daher werde ich dieses Wort von nun an verwenden.
Unter Linux / Unix erhalten Sie den Computernamen von der C-Funktion gethostname()
oder den hostname
Befehl von der Shell oder der HOSTNAME
Umgebungsvariablen in Bash-ähnlichen Shells.
Unter Windows erhalten Sie den Computernamen von der Umgebungsvariablen COMPUTERNAME
oder der Win32- GetComputerName
Funktion.
Java hat keine Möglichkeit, das zu erhalten, was ich als "Computername" definiert habe. Sicher, es gibt Problemumgehungen, wie in anderen Antworten beschrieben, wie zum Beispiel für Windows-Aufrufe System.getenv("COMPUTERNAME")
, aber unter Unix / Linux gibt es keine gute Problemumgehung, ohne auf JNI / JNA oder zurückzugreifen Runtime.exec()
. Wenn Ihnen eine JNI / JNA-Lösung nichts ausmacht, gibt es gethostname4j, das kinderleicht und sehr einfach zu bedienen ist.
Fahren wir mit zwei Beispielen fort, einem von Linux und einem von Solaris, die zeigen, wie Sie leicht in eine Situation geraten können, in der Sie den Computernamen nicht mit Standard-Java-Methoden erhalten können.
Auf einem neu erstellten System, auf dem der Host während der Installation als "Chicago" bezeichnet wurde, ändern wir jetzt den sogenannten Kernel-Hostnamen:
$ hostnamectl --static set-hostname dallas
Jetzt lautet der Kernel-Hostname 'dallas', wie aus dem Befehl hostname hervorgeht:
$ hostname
dallas
Aber wir haben immer noch
$ cat /etc/hosts
127.0.0.1 localhost
127.0.0.1 chicago
Darin liegt keine Fehlkonfiguration. Dies bedeutet lediglich, dass sich der Netzwerkname des Hosts (oder vielmehr der Name der Loopback-Schnittstelle) vom Computernamen des Hosts unterscheidet.
Versuchen Sie nun die Ausführung InetAddress.getLocalHost().getHostName()
und es wird eine java.net.UnknownHostException ausgelöst. Sie stecken im Grunde fest. Es gibt keine Möglichkeit, weder den Wert 'dallas' noch den Wert 'chicago' abzurufen.
Das folgende Beispiel basiert auf Solaris 11.3.
Der Host wurde absichtlich so konfiguriert, dass der Loopback-Name <> Knotenname ist.
Mit anderen Worten haben wir:
$ svccfg -s system/identity:node listprop config
...
...
config/loopback astring chicago
config/nodename astring dallas
und den Inhalt von / etc / hosts:
:1 chicago localhost
127.0.0.1 chicago localhost loghost
und das Ergebnis des Befehls hostname wäre:
$ hostname
dallas
Genau wie im Linux-Beispiel schlägt ein Aufruf von InetAddress.getLocalHost().getHostName()
fehl
java.net.UnknownHostException: dallas: dallas: node name or service name not known
Genau wie im Linux-Beispiel stecken Sie jetzt fest. Es gibt keine Möglichkeit, weder den Wert 'dallas' noch den Wert 'chicago' abzurufen.
Sehr oft werden Sie feststellen, dass InetAddress.getLocalHost().getHostName()
tatsächlich ein Wert zurückgegeben wird, der dem Computernamen entspricht. Es gibt also kein Problem (außer dem zusätzlichen Aufwand für die Namensauflösung).
Das Problem tritt normalerweise in PaaS-Umgebungen auf, in denen ein Unterschied zwischen dem Computernamen und dem Namen der Loopback-Schnittstelle besteht. Zum Beispiel melden Leute Probleme in Amazon EC2.
Ein bisschen Suchen zeigt diesen RFE-Bericht: Link1 , Link2 . Nach den Kommentaren zu diesem Bericht zu urteilen, scheint das Problem jedoch vom JDK-Team weitgehend missverstanden worden zu sein, so dass es unwahrscheinlich ist, dass es behoben wird.
Ich mag den Vergleich in der RFE mit anderen Programmiersprachen.
Umgebungsvariablen können ebenfalls ein nützliches Mittel sein - COMPUTERNAME
unter Windows HOSTNAME
auf den meisten modernen Unix / Linux-Shells.
Siehe: https://stackoverflow.com/a/17956000/768795
Ich verwende diese als "ergänzende" Methoden InetAddress.getLocalHost().getHostName()
, da diese Funktion, wie mehrere Leute betonen, nicht in allen Umgebungen funktioniert.
Runtime.getRuntime().exec("hostname")
ist eine weitere mögliche Ergänzung. Zu diesem Zeitpunkt habe ich es noch nicht benutzt.
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;
StringUtils
, wird es vom Apache commons-lang-Projekt bereitgestellt. Die Verwendung oder ähnliches wird dringend empfohlen.
System.getenv("HOSTNAME")
kam auf dem Mac über Beanshell für Java null heraus, wurde aber PATH
ok extrahiert. Ich könnte es auch echo $HOSTNAME
auf einem Mac tun , nur System.getenv ("HOSTNAME") scheint ein Problem zu haben. Seltsam.
Der portabelste Weg, um den Hostnamen des aktuellen Computers in Java abzurufen, ist wie folgt:
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);
}
}
Wenn Sie nicht gegen die Verwendung einer externen Abhängigkeit von maven central sind, habe ich gethostname4j geschrieben, um dieses Problem für mich selbst zu lösen. Es verwendet nur JNA, um die Funktion gethostname von libc aufzurufen (oder den Computernamen unter Windows abzurufen) und gibt sie als Zeichenfolge an Sie zurück.
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();
}
}
}
}
Nur einzeilig ... plattformübergreifend (Windows-Linux-Unix-Mac (Unix)) [Funktioniert immer, kein DNS erforderlich]:
String hostname = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
.readLine();
Du bist fertig !!
InetAddress.getLocalHost (). GetHostName () ist der beste Ausweg, da dies die beste Abstraktion auf Entwicklerebene ist.