Méthode recommandée pour obtenir le nom d'hôte en Java

lequel des suivants est le meilleur et le moyen le plus portable pour obtenir le nom d'hôte de L'ordinateur actuel en Java?

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

vs

InetAddress.getLocalHost().getHostName()

228
demandé sur Malt 2011-09-08 17:20:37

10 réponses

Strictement parlant, vous n'avez pas le choix, mais appelant hostname(1) ou sur Unix gethostname(2) . C'est le nom de votre ordinateur. Toute tentative de déterminer le nom d'hôte par une adresse IP comme celle-ci

InetAddress.getLocalHost().getHostName()

est voué à l'échec dans certaines circonstances:

  • il se peut que l'adresse IP ne se résolve en aucun nom. Une mauvaise configuration du DNS, une mauvaise configuration du système ou une mauvaise configuration du fournisseur peut en être la raison.
  • A nom dans le DNS peut avoir de nombreux alias appelés CNAMEs. Ceux-ci ne peuvent être résolus correctement que dans un seul sens: du nom à l'adresse. Le sens inverse est ambigu. Quel est le nom "officiel"?
  • un hôte peut avoir beaucoup d'adresses IP différentes - et chaque adresse peut avoir beaucoup de noms différents. Deux cas courants sont: un port ethernet a plusieurs adresses IP "logiques" ou l'ordinateur a plusieurs ports ethernet. Il est configurable qu'ils partagent une adresse IP ou qu'ils aient des adresses IP différentes. Ceci est appelé "multi-hôtes".
  • un nom dans le DNS peut résoudre à plusieurs adresses IP. Et toutes ces adresses ne doivent pas être situées sur le même ordinateur! (Cas d'utilisation: Une simple forme d'équilibrage de charge)
  • ne parlons même pas des adresses IP dynamiques.

ne confondez pas non plus le nom D'une adresse IP avec le nom de l'hôte (nom d'hôte). Une métaphore pourrait le rendre plus clair:

Il est d'une grande ville (serveur) dite "de Londres". À l'intérieur des murs de la ville, il se passe beaucoup de choses. La ville a plusieurs portes (adresses IP). Chaque porte a un nom ("Porte du Nord", "la Rivière" à la Porte, "Southampton"à la Porte...), mais le nom de la porte n'est pas le nom de la ville. En outre, vous ne pouvez pas déduire le nom de la ville en utilisant le nom d'une porte - "Porte Nord" attraperait la moitié des grandes villes et pas seulement une ville. Cependant - un étranger (paquet IP) marche le long de la rivière et demande à un local: "Je vous avez une adresse étrange: "Rivergate, deuxième à gauche, troisième maison". Pouvez-vous m'aider?"Le local dit:" Bien sûr, vous êtes sur la bonne route, il suffit d'aller de l'avant et vous arriverez à votre destination dans une demi-heure."

Cela illustre assez bien je pense.

La bonne nouvelle, c'est: réel nom d'hôte est habituellement pas nécessaire. Dans la plupart des cas tout nom qui se résout dans une adresse IP sur cet hôte ne pourra le faire. (L'étranger pourrait entrer dans la ville par Northgate, mais les habitants serviables traduire la partie" deuxième gauche".)

si les cases de coin restantes vous devez utiliser le source" définitive de ce paramètre de configuration - qui est la fonction C gethostname(2) . Cette fonction est aussi appelée par le programme hostname .

296
répondu A.H. 2011-10-17 21:50:48

InetAddress.getLocalHost().getHostName() est le moyen le plus portable.

exec("hostname") appelle en fait le système d'exploitation à exécuter la commande hostname .

voici quelques autres réponses sur SO:

EDIT: Vous devriez jeter un oeil à A. H. la réponse de ou Arnout Engelen la réponse de pour plus de détails sur pourquoi cela pourrait ne pas fonctionner comme prévu, en fonction de votre situation. Comme réponse pour cette personne qui a spécifiquement demandé portable, je pense toujours getHostName() est très bien, mais ils soulèvent quelques bons points qui devraient être considérés.

86
répondu Nick Knowlson 2017-05-23 12:26:33

comme d'autres l'ont noté, obtenir le nom d'hôte basé sur la résolution DNS n'est pas fiable.

comme cette question est malheureusement toujours pertinente dans 2018 , j'aimerais partager avec vous ma solution indépendante du réseau, avec quelques essais sur différents systèmes.

le code suivant essaie de faire ce qui suit:

  • À La Windows

    1. Lire la COMPUTERNAME variable d'environnement jusqu'à System.getenv() .

    2. exécuter hostname.exe et lire la réponse

  • À La Linux

    1. Lire la HOSTNAME variable d'environnement par System.getenv()

    2. exécuter hostname et lire la réponse

    3. Lire /etc/hostname (pour ce faire, j'exécute cat puisque l'extrait contient déjà du code à exécuter et à lire. Il serait cependant préférable de simplement lire le fichier).

le 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() : "";
    }
}

résultats pour différents systèmes d'exploitation:

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 Celui-ci est un peu étrange puisque echo $HOSTNAME renvoie le nom d'hôte correct, mais System.getenv("HOSTNAME") ne fait pas:

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

EDIT: Selon legolas108 , System.getenv("HOSTNAME") fonctionne sur Ubuntu 14.04 si vous exécutez export HOSTNAME avant l'exécution de la Le code Java.

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
"

les noms de machines ont été remplacés mais j'ai gardé la majuscule et la structure. Notez la nouvelle ligne supplémentaire lors de l'exécution de hostname , vous pourriez avoir à en tenir compte dans certains cas.

37
répondu Malt 2018-02-06 08:32:16

InetAddress.getLocalHost().getHostName() est mieux (comme l'a expliqué Nick), mais pas encore très bonne

un hôte peut être connu sous de nombreux noms d'hôtes différents. Habituellement, vous chercherez le nom d'hôte de votre hôte dans un contexte spécifique.

par exemple, dans une application web, vous pourriez être à la recherche du nom d'hôte utilisé par celui qui a émis la requête que vous manipulez actuellement. Comment trouver au mieux cela dépend du cadre que vous utilisez pour votre web application.

dans une sorte d'autre service Internet, vous voudrez le nom d'hôte de votre service est disponible par le biais de "l'extérieur". En raison de proxies, pare-feu, etc cela pourrait même ne pas être un nom d'hôte sur la machine sur laquelle votre service est installé - vous pourriez essayer de trouver un défaut raisonnable, mais vous devriez certainement rendre cette configurable pour celui qui installe cela.

23
répondu Arnout Engelen 2011-09-08 19:34:37

variables D'environnement peuvent également fournir un moyen utile -- COMPUTERNAME sur Windows, HOSTNAME sur la plupart des interpréteurs de commandes Unix/Linux modernes.

voir: https://stackoverflow.com/a/17956000/768795

je les utilise comme méthodes" supplémentaires "à InetAddress.getLocalHost().getHostName() , car comme plusieurs personnes le font remarquer, cette fonction ne fonctionne pas dans tous les environnements.

Runtime.getRuntime().exec("hostname") est un autre complément possible. À a ce stade, je ne l'ai pas utilisé.

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;
10
répondu Thomas W 2017-05-23 12:34:47

le moyen le plus portable pour obtenir le nom d'hôte de L'ordinateur courant en Java est le suivant:

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);
    }
}
6
répondu Desta Haileselassie Hagos 2013-12-17 13:52:13

bien que ce sujet ait déjà reçu une réponse, il y a plus à dire.

tout d'abord: il est clair que nous avons besoin de définitions ici. Le InetAddress.getLocalHost().getHostName() vous donne le nom de l'hôte vu du point de vue du réseau . Les problèmes de cette approche sont bien documentés dans les autres réponses: elle nécessite souvent une recherche DNS, elle est ambiguë si l'hôte a plusieurs interfaces réseau et elle échoue tout simplement parfois (voir ci-dessous).

mais sur n'importe quel OS il y a aussi un autre nom. Un nom de l'hôte est défini très tôt dans le processus de démarrage, bien avant que le réseau est initialisé. Windows se réfère à cela comme computername , Linux l'appelle nom d'hôte du noyau et Solaris utilise le mot nodename . Je préfère le mot computername , donc je vais utiliser ce mot à partir de maintenant.

Trouver le nom de l'ordinateur

  • sur Linux/Unix , le nom computername est ce que vous obtenez de la fonction C gethostname() , ou de la commande hostname de shell ou de la variable d'environnement HOSTNAME dans des shells de type Bash.

  • sous Windows le nom de computername est ce que vous obtenez de la variable d'environnement COMPUTERNAME ou Win32 GetComputerName fonction.

Java n'a aucun moyen d'obtenir ce que j'ai défini comme "computername'. bien sûr, il y a des solutions de rechange comme décrit dans d'autres réponses, comme pour Windows appelant System.getenv("COMPUTERNAME") , mais sur Unix/Linux il n'y a pas de bonne solution de contournement sans recourir à JNI/JNA ou Runtime.exec() . Si une solution JNI/JNA ne vous dérange pas, alors il y a gethostname4j qui est très simple et très facile à utiliser.

passons à deux exemples, L'un de Linux et L'autre de Solaris, qui montrent comment vous pouvez facilement entrer dans une situation où vous ne pouvez pas obtenir le nom de computername en utilisant les méthodes Java standard.

exemple Linux

sur un système nouvellement créé, où l'hôte lors de l'installation a été nommé 'chicago', nous changeons maintenant le nom de l'hôte du noyau:

$ hostnamectl --static set-hostname dallas

maintenant le nom de l'hôte du noyau est 'dallas', comme le montre la commande hostname:

$ hostname
dallas

mais nous avons encore

$ cat /etc/hosts
127.0.0.1   localhost
127.0.0.1   chicago

il n'y a pas d'erreur de configuration. Cela signifie simplement que le nom de réseau de l'hôte (ou plutôt le nom de l'interface loopback) est différent du nom informatique de l'hôte.

maintenant, essayez d'exécuter InetAddress.getLocalHost().getHostName() et il lancera java.net.UnknownHostException. Tu es pratiquement coincé. Il n'y a aucun moyen de récupérer ni la valeur "dallas" ni la valeur "chicago".

Solaris exemple

L'exemple ci-dessous est basé sur Solaris 11.3.

l'hôte a été délibérément configuré de sorte que le nom du loopback <> nodename.

en d'autres termes nous avons:

$ svccfg -s system/identity:node listprop config
...
...
config/loopback             astring        chicago
config/nodename             astring        dallas

et le contenu de / etc / hosts:

:1 chicago localhost
127.0.0.1 chicago localhost loghost

et le résultat de la commande hostname:

$ hostname
dallas

Tout comme dans L'exemple Linux, un appel à InetAddress.getLocalHost().getHostName() échouera avec

java.net.UnknownHostException: dallas:  dallas: node name or service name not known

tout comme L'exemple de Linux, vous êtes maintenant bloqué. Il n'y a aucun moyen de récupérer ni la valeur "dallas" ni la valeur "chicago".

Quand allez-vous vraiment lutter avec cela?

très souvent, vous trouverez que InetAddress.getLocalHost().getHostName() retournera en effet une valeur qui est égale au nom informatique. Donc il n'y a pas de problème (sauf pour l'ajout surcharge de la résolution de nom).

le problème se pose typiquement dans les environnements PaaS où il y a une différence entre computername et le nom de l'interface loopback. Par exemple, les gens signalent des problèmes en Amazonie EC2.

rapports de bogue /RFE

un peu de recherche révèle ce rapport RFE: link1 , link2 . Toutefois, à en juger par les commentaires sur ce rapport, le problème semble ont été en grande partie incompris par le JDK de l'équipe, il est donc peu probable qu'il sera abordée.

j'aime la comparaison de la RFE à d'autres langages de programmation.

5
répondu peterh 2017-02-18 10:28:51
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
répondu ThuVien247.net 2012-04-17 09:41:19

si vous n'êtes pas contre l'utilisation d'une dépendance externe de maven central, j'ai écrit gethostname4j pour résoudre ce problème pour moi-même. Il utilise JNA pour appeler la fonction gethostname de libc (ou obtient le nom ComputerName sur Windows) et vous le renvoie sous forme de chaîne de caractères.

https://github.com/mattsheppard/gethostname4j

2
répondu Matt Sheppard 2017-01-08 19:11:56

Inetadress.getLocalHost ().getHostName () est le meilleur moyen de sortir des deux car c'est la meilleure abstraction au niveau du développeur.

-2
répondu java_mouse 2011-10-13 14:07:54