wake-up-neo.com

Empfohlene Methode zum Abrufen des Hostnamens in Java

Welche der folgenden Methoden ist die beste und portabelste, um den Hostnamen des aktuellen Computers in Java abzurufen?

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

vs

InetAddress.getLocalHost().getHostName()

254
Mahendra

Genau genommen haben Sie keine andere Wahl, als entweder hostname(1) oder - unter Unix gethostname(2) aufzurufen. 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:

  • Die IP-Adresse wird möglicherweise nicht in einen Namen aufgelöst. Ein fehlerhaftes DNS-Setup, ein fehlerhaftes System-Setup oder ein fehlerhaftes Provider-Setup können die Ursache sein.
  • Ein Name in DNS kann viele Aliase haben, die CNAMEs genannt werden. Diese können nur in eine Richtung richtig gelöst werden: Name zu Adresse. Die umgekehrte Richtung ist nicht eindeutig. Welcher ist der "offizielle" Name?
  • Ein Host kann viele verschiedene IP-Adressen haben - und jede Adresse kann viele verschiedene Namen haben. Zwei häufige Fälle sind: Ein Ethernet-Port verfügt über mehrere "logische" IP-Adressen, oder der Computer verfügt über mehrere Ethernet-Ports. Es ist konfigurierbar, ob sie eine IP gemeinsam nutzen oder unterschiedliche IPs haben. Dies nennt man "multihomed".
  • Ein Name in DNS kann in mehrere IP-Adressen aufgelöst werden. Und nicht alle diese Adressen müssen sich auf demselben Computer befinden! (Usecase: Eine einfache Form des Lastausgleichs)
  • Lassen Sie uns nicht einmal über dynamische IP-Adressen sprechen.

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 - "North Gate" fängt die Hälfte der größeren Städte und nicht nur eine Stadt. Allerdings - ein Fremder (IP-Paket) geht den Fluss entlang und fragt einen Einheimischen: "Ich habe eine seltsame Adresse: 'Rivergate, zweites Haus links, drittes Haus'. Können Sie mir helfen?" Der Einheimische sagt: "Natürlich sind Sie auf dem richtigen Weg, gehen Sie einfach weiter 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 notwendig. In den meisten Fällen ist jeder Name ausreichend, der auf diesem Host in eine IP-Adresse aufgelöst wird. (Der Fremde könnte die Stadt durch Northgate betreten, aber hilfreiche Einheimische übersetzen den "2. linken" Teil.)

In den übrigen Eckfällen müssen Sie die definitive Quelle dieser Konfigurationseinstellung verwenden - das ist die C-Funktion gethostname(2). Diese Funktion wird auch vom Programm hostname aufgerufen.

317
A.H.

InetAddress.getLocalHost().getHostName() ist der portablere Weg.

exec("hostname") ruft das Betriebssystem auf, um den Befehl hostname auszuführen.

Hier sind ein paar andere verwandte Antworten auf SO:

BEARBEITEN: Weitere Informationen finden Sie unter Antwort von AH oder Antwort von Arnout Engelen Warum dies möglicherweise nicht wie erwartet funktioniert, hängt von Ihrer Situation ab. Als Antwort für diese Person, die speziell das Portable angefordert hat, denke ich immer noch, dass getHostName() in Ordnung ist, aber sie bringen einige gute Punkte vor, die berücksichtigt werden sollten.

90
Nick Knowlson

Wie andere angemerkt haben, ist das Abrufen des Hostnamens basierend auf der DNS-Auflösung unzuverlässig.

Da diese Frage im Jahr 2018 leider noch aktuell ist , möchte ich Ihnen meine netzwerkunabhängige Lösung mit einigen Testläufen auf verschiedenen Systemen mitteilen.

Der folgende Code versucht Folgendes zu tun:

  • Unter Windows

    1. Lesen Sie die Umgebungsvariable COMPUTERNAME durch System.getenv().

    2. Führen Sie hostname.exe Aus und lesen Sie die Antwort

  • Unter Linux

    1. Lies die Umgebungsvariable HOSTNAME durch System.getenv()

    2. Führen Sie hostname aus und lesen Sie die Antwort

    3. Lesen Sie /etc/hostname (Dazu führe ich cat aus, da das Snippet bereits auszuführenden und zu lesenden Code enthält. Ein einfaches Lesen der Datei wäre jedoch besser).

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 Dies ist etwas seltsam, da echo $HOSTNAME Den korrekten 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: Laut legolas108 funktioniert System.getenv("HOSTNAME") unter Ubuntu 14.04, wenn Sie export HOSTNAME, bevor Sie den Java - Code ausführen.

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 die Groß- und Kleinschreibung und die Struktur wurden beibehalten. Beachten Sie bei der Ausführung von hostname den zusätzlichen Zeilenumbruch, den Sie in einigen Fällen möglicherweise berücksichtigen müssen.

50
Malt

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 beispielsweise nach dem Hostnamen, der von dem Benutzer verwendet wird, der die Anforderung ausgegeben hat, die Sie gerade bearbeiten. Wie Sie dies am besten finden, hängt davon ab, welches Framework Sie für Ihre Webanwendung verwenden.

Bei einer anderen Art von Internet-Service möchten Sie, dass der Hostname, über den Ihr Service verfügbar ist, von außen angezeigt wird. Aufgrund von Proxys, Firewalls usw. ist dies möglicherweise nicht einmal ein Hostname auf dem Computer, auf dem Ihr Dienst installiert ist. Möglicherweise möchten Sie einen vernünftigen Standard festlegen, aber Sie sollten ihn auf jeden Fall für jeden konfigurierbar machen, der dies installiert.

23
Arnout Engelen

Obwohl dieses Thema bereits beantwortet wurde, gibt es noch mehr zu sagen.

Zuallererst: Wir brauchen hier natürlich einige Definitionen. Die Funktion InetAddress.getLocalHost().getHostName() gibt Ihnen den Namen des Hosts aus der Sicht des Netzwerks an. 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 er einfach fehl (siehe unten).

Aber auf jedem Betriebssystem gibt es auch einen anderen Namen. Ein Name des Hosts, der sehr früh im Startprozess definiert wird, lange bevor das Netzwerk initialisiert wird. Windows bezeichnet dies als Computername, Linux nennt es Kernel-Hostname und Solaris verwendet das Wort Knotenname. Ich mag das Wort am liebsten Computername, also werde ich dieses Wort von nun an verwenden.

Suche nach dem Computernamen

  • Unter Linux/Unix ist der Computername das, was Sie von der C-Funktion gethostname() oder dem Befehl hostname von der Shell oder der Umgebungsvariablen HOSTNAME in Bash-ähnlichen Shells erhalten.

  • Unter Windows entspricht der Computername der Funktion der Umgebungsvariablen COMPUTERNAME oder Win32 GetComputerName.

Java hat keine Möglichkeit, an das zu gelangen, was ich als 'Computername' definiert habe. Sicher, es gibt Workarounds, wie sie in anderen Antworten beschrieben wurden, zum Beispiel für Windows, das System.getenv("COMPUTERNAME") aufruft, aber on Unter Unix/Linux gibt es keine gute Lösung, wenn Sie nicht auf JNI/JNA oder Runtime.exec() zurückgreifen. Wenn Ihnen eine JNI/JNA-Lösung nichts ausmacht, gibt es gethostname4j , das kinderleicht und sehr benutzerfreundlich ist.

Lassen Sie uns mit zwei Beispielen fortfahren, eines von Linux und eines von Solaris, die zeigen, wie Sie leicht in eine Situation geraten können, in der Sie den Computernamen nicht mit den Standardmethoden Java) erhalten können.

Linux-Beispiel

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

Nun lautet der Hostname des Kernels 'dallas', wie aus dem Befehl hostname hervorgeht:

$ hostname
dallas

Aber wir haben es 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 besser gesagt der Name der Loopback-Schnittstelle) vom Computernamen des Hosts unterscheidet.

Versuchen Sie nun, InetAddress.getLocalHost().getHostName() auszuführen, und es wird Java.net.UnknownHostException ausgelöst. Du steckst im Grunde fest. Es gibt keine Möglichkeit, weder den Wert "Dallas" noch den Wert "Chicago" abzurufen.

Solaris-Beispiel

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.

Wann werden Sie wirklich damit zu kämpfen haben?

Sehr oft werden Sie feststellen, dass InetAddress.getLocalHost().getHostName() tatsächlich einen Wert zurückgibt, der dem Computernamen entspricht. Es gibt also kein Problem (mit Ausnahme des zusätzlichen Aufwands 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.

Fehler-/RFE-Meldungen

Ein wenig Suche enthüllt diesen RFE-Bericht: link1 , link2 . Den Kommentaren zu diesem Bericht nach zu urteilen, scheint das Problem vom JDK-Team jedoch weitgehend missverstanden worden zu sein, so dass es unwahrscheinlich ist, dass es behoben wird.

Ich mag den Vergleich in der RFE zu anderen Programmiersprachen.

11
peterh

Umgebungsvariablen können auch 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 zu InetAddress.getLocalHost().getHostName(), da, wie mehrere Leute darauf hinweisen, diese Funktion 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;
11
Thomas W

Die portabelste Methode, um den Hostnamen des aktuellen Computers in Java zu ermitteln, lautet 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);
    }
}
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();
            }
        }
    }
}
3
ThuVien247.net

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. Mit JNA wird lediglich die Funktion gethostname von libc aufgerufen (oder der Computername unter Windows abgerufen) und als Zeichenfolge an Sie zurückgegeben.

https://github.com/mattsheppard/gethostname4j

2
Matt Sheppard