Quel est le moyen le plus portable et le plus simple d’obtenir le nom d’hôte de l’ordinateur actuel en Java?
Runtime.getRuntime().exec("hostname")
contre
InetAddress.getLocalHost().getHostName()
À proprement parler, vous n'avez pas d'autre choix que d'appeler soit hostname(1)
, soit - sous Unix gethostname(2)
. Ceci 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:
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 y a une grande ville (serveur) appelée "Londres". À l'intérieur des murs de la ville, beaucoup de choses se passent. La ville a plusieurs portes (adresses IP). Chaque porte a un nom ("North Gate", "River Gate", "Southampton Gate" ...) mais le nom de la porte n’est pas le nom de la ville. Aussi, vous ne pouvez pas déduire le nom de la ville en utilisant le nom d'une porte - "North Gate" prendrait la moitié des plus grandes villes et pas seulement une ville. Cependant - un étranger (paquet IP) marche le long de la rivière et demande à un local: "J'ai une adresse étrange:" Rivergate, deuxième à gauche, troisième maison ". Pouvez-vous m'aider?" La section locale a déclaré: "Bien sûr, vous êtes sur la bonne route, continuez et vous arriverez à destination dans une demi-heure."
Cela illustre bien ce que je pense.
La bonne nouvelle est que: le nom d'hôte réel est généralement pas nécessaire. Dans la plupart des cas, tout nom qui se résout en une adresse IP sur cet hôte fera l'affaire. (L'étranger peut entrer dans la ville par Northgate, mais les habitants, très serviables, traduisent la partie "2e à gauche".)
Si les coins restants correspondent, vous devez utiliser la source définitive de ce paramètre de configuration - qui est la fonction C gethostname(2)
. Cette fonction est également appelée par le programme hostname
.
InetAddress.getLocalHost().getHostName()
est la méthode la plus portable.
exec("hostname")
appelle en fait le système d'exploitation pour exécuter la commande hostname
.
Voici quelques autres réponses sur SO:
EDIT: Vous devriez jeter un oeil à réponse d'AH ou réponse d'Arnout Engelen pour plus de détails pourquoi cela pourrait ne pas fonctionner comme prévu, selon votre situation. Pour répondre à cette personne qui a spécifiquement demandé le portable, je pense toujours que getHostName()
va bien, mais ils soulèvent quelques points intéressants à prendre en compte.
Comme d'autres l'ont fait remarquer, l'obtention du nom d'hôte en fonction de la résolution DNS n'est pas fiable.
Comme cette question est malheureusement toujours d'actualité pour 2018 , j'aimerais partager avec vous ma solution indépendante du réseau, avec quelques essais sur différents systèmes.
Le code suivant tente de faire ce qui suit:
Sur Windows
Lisez la variable d'environnement COMPUTERNAME
dans System.getenv()
.
Exécutez hostname.exe
et lisez la réponse.
Sur Linux
Lisez la variable d’environnement HOSTNAME
dans System.getenv()
Exécutez hostname
et lisez la réponse
Lisez /etc/hostname
(pour ce faire, j'exécute cat
car l'extrait de code contient déjà du code à exécuter et à lire. Il serait préférable de lire simplement 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:
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 de l'exécuter. 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 capitalisation et la structure. Notez la nouvelle ligne supplémentaire lors de l'exécution de hostname
, vous devrez peut-être en tenir compte dans certains cas.
InetAddress.getLocalHost().getHostName()
est meilleur (comme l'explique Nick), mais pas très bon
Un hôte peut être connu sous plusieurs noms d'hôte différents. Généralement, vous recherchez le nom d'hôte de votre hôte dans un contexte spécifique.
Par exemple, dans une application Web, vous pouvez rechercher le nom d'hôte utilisé par celui qui a émis la demande que vous êtes en train de traiter. La meilleure façon de le trouver dépend du framework que vous utilisez pour votre application Web.
Dans certains types de services Internet, vous souhaitez que le nom d’hôte par lequel votre service est disponible soit accessible depuis l’extérieur. En raison des proxies, des pare-feu, etc., il se peut même que ce ne soit pas un nom d'hôte sur la machine sur laquelle votre service est installé. Vous pouvez essayer de définir un paramètre par défaut raisonnable, mais vous devez absolument le rendre configurable pour quiconque l'installe.
Bien que ce sujet ait déjà été répondu, il y a plus à dire.
Tout d'abord: il est clair que nous avons besoin de définitions ici. La InetAddress.getLocalHost().getHostName()
vous donne le nom de l'hôte vu du point de vue du réseau . Les problèmes avec cette approche sont bien documentés dans les autres réponses: cela nécessite souvent une recherche DNS, il est ambigu si l’hôte possède plusieurs interfaces réseau et c’est tout simplement un échec parfois (voir ci-dessous).
Mais sur tout OS, il y a aussi un autre nom. Nom de l'hôte défini très tôt dans le processus de démarrage, bien avant l'initialisation du réseau. Windows appelle cela nom_ordinateur, Linux l'appelle nom d'hôte du noya et Solaris utilise le mot nom_noeud. J'aime mieux le mot nom_ordinateur, je vais donc utiliser ce mot à partir de maintenant.
Sous Linux/Unix, le nom d’ordinateur correspond à ce que vous obtenez avec la commande gethostname()
de la fonction C ou hostname
de Shell ou la variable d’environnement HOSTNAME
dans des shells de type Bash.
Sous Windows, le nom d’ordinateur correspond à ce que vous obtenez à partir de la variable d’environnement COMPUTERNAME
ou de la fonction Win32 GetComputerName
.
Java n'a aucun moyen d'obtenir ce que j'ai défini comme "nom_ordinateur". Bien sûr, il existe des solutions de contournement décrites dans d'autres réponses, comme pour l'appel de Windows System.getenv("COMPUTERNAME")
, mais sous Unix/Linux, pas de bonne solution de contournement sans recourir à JNI/JNA ou à Runtime.exec()
. Si vous ne craignez pas une solution JNI/JNA, alors il y a gethostname4j , ce qui est extrêmement simple et très facile à utiliser.
Passons maintenant à deux exemples, l'un sous Linux et l'autre sous Solaris, qui montrent comment vous pouvez facilement vous retrouver dans une situation dans laquelle vous ne pouvez pas obtenir le nom d'ordinateur à l'aide des méthodes standard Java.
Sur un système nouvellement créé, où l'hôte lors de l'installation a été nommé "chicago", nous modifions maintenant le nom d'hôte du noyau:
$ hostnamectl --static set-hostname dallas
Maintenant, le nom d'hôte du noyau est 'dallas', comme il ressort de 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 aucune mauvaise configuration dans cela. Cela signifie simplement que le nom réseau de l'hôte (ou plutôt le nom de l'interface de bouclage) est différent du nom de l'ordinateur de l'hôte.
Maintenant, essayez d’exécuter InetAddress.getLocalHost().getHostName()
et cela jettera Java.net.UnknownHostException. Vous êtes fondamentalement coincé. Il n'y a aucun moyen de récupérer ni la valeur "dallas" ni la valeur "chicago".
L'exemple ci-dessous est basé sur Solaris 11.3.
L'hôte a été délibérément configuré pour que le nom de boucle <> nom_noeud.
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 serait:
$ hostname
dallas
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".
Très souvent, vous constaterez que InetAddress.getLocalHost().getHostName()
renverra effectivement une valeur égale au nom de l'ordinateur. Donc, il n'y a pas de problème (à l'exception de la surcharge de résolution de nom).
Le problème se pose généralement dans les environnements PaaS où il existe une différence entre nom_ordinateur et nom de l'interface de bouclage. Par exemple, des personnes signalent des problèmes dans Amazon EC2.
Un peu de recherche révèle ce rapport RFE: link1 , link2 . Cependant, à en juger par les commentaires sur ce rapport, la question semble avoir été largement mal comprise par l'équipe du JDK, il est donc peu probable que le problème soit résolu.
J'aime la comparaison dans le RFE avec d'autres langages de programmation.
Les variables d'environnement peuvent également constituer un moyen utile - COMPUTERNAME
sous Windows, HOSTNAME
sur la plupart des shells Unix/Linux modernes.
Voir: https://stackoverflow.com/a/17956000/768795
J'utilise ces méthodes "supplémentaires" pour InetAddress.getLocalHost().getHostName()
, car, comme plusieurs personnes le signalent, cette fonction ne fonctionne pas dans tous les environnements.
Runtime.getRuntime().exec("hostname")
est un autre complément possible. À 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;
Le moyen le plus portable d'obtenir le nom d'hôte de l'ordinateur actuel dans 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);
}
}
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();
}
}
}
}
Si vous n'êtes pas contre l'utilisation d'une dépendance externe à partir de maven central, j'ai écrit gethostname4j pour résoudre ce problème moi-même. Il utilise simplement la JNA pour appeler la fonction gethostname de libc (ou obtient le nom de l'ordinateur sous Windows) et vous le renvoie sous forme de chaîne.