Który z poniższych jest najlepszym i najbardziej przenośnym sposobem na uzyskanie nazwy hosta bieżącego komputera w Javie?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
Który z poniższych jest najlepszym i najbardziej przenośnym sposobem na uzyskanie nazwy hosta bieżącego komputera w Javie?
Runtime.getRuntime().exec("hostname")
vs
InetAddress.getLocalHost().getHostName()
Odpowiedzi:
Ściśle mówiąc - nie masz wyboru, musisz zadzwonić albo
hostname(1)
- na Uniksiegethostname(2)
. To jest nazwa twojego komputera. Każda próba ustalenia nazwy hosta na podstawie adresu IP takiego jak tenw niektórych okolicznościach może się nie powieść:
Nie należy także mylić nazwy adresu IP z nazwą hosta (nazwa hosta). Metafora może to wyjaśnić:
Myślę, że to ilustruje.
Dobra wiadomość jest taka: prawdziwa nazwa hosta zwykle nie jest konieczna. W większości przypadków wystarczy nazwa, która zamienia się w adres IP na tym hoście. (Nieznajomy może wejść do miasta przez Northgate, ale pomocni miejscowi tłumaczą część „2. lewa”).
W przypadku pozostałych przypadkach narożnych należy użyć ostateczne źródło tego ustawienia konfiguracji - co jest funkcja C
gethostname(2)
. Ta funkcja jest również wywoływana przez programhostname
.źródło
InetAddress.getLocalHost().getHostName()
jest bardziej przenośnym sposobem.exec("hostname")
faktycznie woła system operacyjny, aby wykonaćhostname
polecenie.Oto kilka innych powiązanych odpowiedzi na temat SO:
EDYCJA: Powinieneś spojrzeć na odpowiedź AH lub odpowiedź Arnouta Engelena, aby dowiedzieć się, dlaczego może to nie działać zgodnie z oczekiwaniami, w zależności od twojej sytuacji. W odpowiedzi dla tej osoby, która specjalnie poprosiła o urządzenie przenośne, nadal uważam, że
getHostName()
jest w porządku, ale przynoszą one kilka dobrych punktów, które należy wziąć pod uwagę.źródło
InetAddress.getLocalHost()
w niektórych przypadkach zwraca urządzenie sprzężenia zwrotnego. W takim przypadkugetHostName()
zwraca „localhost”, co nie jest zbyt przydatne.Jak zauważyli inni, uzyskanie nazwy hosta na podstawie rozpoznania DNS jest zawodne.
Ponieważ to pytanie jest niestety nadal aktualne w 2018 r. , Chciałbym podzielić się z Wami moim niezależnym od sieci rozwiązaniem z niektórymi testami przeprowadzanymi na różnych systemach.
Poniższy kod próbuje wykonać następujące czynności:
W systemie Windows
Przeczytaj
COMPUTERNAME
zmienną środowiskowąSystem.getenv()
.Wykonaj
hostname.exe
i przeczytaj odpowiedźW systemie Linux
Przeczytaj
HOSTNAME
zmienną środowiskowąSystem.getenv()
Wykonaj
hostname
i przeczytaj odpowiedźPrzeczytaj
/etc/hostname
(w tym celu wykonuję,cat
ponieważ fragment zawiera już kod do wykonania i odczytu. Lepiej byłoby po prostu odczytać plik).Kod:
Wyniki dla różnych systemów operacyjnych:
macOS 10.13.2
OpenSuse 13.1
Ubuntu 14.04 LTS Ten jest dość dziwny, ponieważ
echo $HOSTNAME
zwraca prawidłową nazwę hosta, aleSystem.getenv("HOSTNAME")
nie:EDYCJA: Według legolas108 ,
System.getenv("HOSTNAME")
działa na Ubuntu 14.04, jeśli uruchomiszexport HOSTNAME
przed uruchomieniem kodu Java.System Windows 7
Windows 10
Nazwy komputerów zostały zastąpione, ale zachowałem wielkie litery i strukturę. Zwróć uwagę na dodatkowy znak nowej linii podczas wykonywania
hostname
, w niektórych przypadkach może być konieczne wzięcie go pod uwagę.źródło
export HOSTNAME
przed uruchomieniem kodu Java na Ubuntu 14.04 LTS jest on również zwracany przezSystem.getenv("HOSTNAME")
.export HOSTNAME
aby Java mogła z niego korzystać? Myślałem, że powinna to być domyślna zmienna env jak PATH.\A
ogranicznik to tylko włamanie do odczytu całego InputStream za pomocąScanner
.InetAddress.getLocalHost().getHostName()
jest lepszy (jak wyjaśnia Nick), ale wciąż niezbyt dobryJeden host może być znany pod wieloma różnymi nazwami hostów. Zazwyczaj będziesz szukał nazwy hosta, którą host ma w określonym kontekście.
Na przykład w aplikacji internetowej możesz szukać nazwy hosta używanej przez osobę, która wysłała aktualnie obsługiwane żądanie. Jak najlepiej to znaleźć, zależy od tego, którego frameworku używasz w swojej aplikacji internetowej.
W jakiejś innej usłudze internetowej potrzebujesz nazwy hosta, za pośrednictwem której Twoja usługa jest dostępna z „zewnątrz”. Z powodu serwerów proxy, zapór ogniowych itp. Może to nawet nie być nazwa hosta na komputerze, na którym zainstalowana jest usługa - możesz spróbować znaleźć rozsądne ustawienie domyślne, ale zdecydowanie powinieneś skonfigurować tę opcję dla każdego, kto ją zainstaluje.
źródło
Chociaż na ten temat już udzielono odpowiedzi, jest więcej do powiedzenia.
Po pierwsze: najwyraźniej potrzebujemy tutaj kilku definicji.
InetAddress.getLocalHost().getHostName()
Daje nazwę hosta, jak widać z perspektywy sieci . Problemy z tym podejściem są dobrze udokumentowane w innych odpowiedziach: często wymaga wyszukiwania DNS, niejednoznaczne jest, jeśli host ma wiele interfejsów sieciowych, a czasami po prostu czasami zawodzi (patrz poniżej).Ale w każdym systemie operacyjnym jest też inna nazwa. Nazwa hosta, która jest definiowana na bardzo wczesnym etapie procesu rozruchu, na długo przed zainicjowaniem sieci. Windows określa to mianem nazwa_komputera , Linux nazywa ją nazwą hosta jądra, a Solaris używa słowa nazwa_węzła . Najbardziej podoba mi się słowo nazwa_komputera , więc odtąd będę go używać.
Znajdowanie nazwy komputera
W Linux / Unix nazwa komputera jest tym, co otrzymujesz z funkcji C
gethostname()
lubhostname
polecenia z powłoki lubHOSTNAME
zmiennej środowiskowej w powłokach typu Bash.W systemie Windows nazwa komputera to nazwa zmiennej środowiskowej
COMPUTERNAME
lubGetComputerName
funkcji Win32 .Java nie ma możliwości uzyskania tego, co zdefiniowałem jako „nazwa komputera”. Oczywiście istnieją obejścia opisane w innych odpowiedziach, na przykład w przypadku wywoływania systemu Windows
System.getenv("COMPUTERNAME")
, ale w systemach Unix / Linux nie można obejść tego problemu bez uciekania się do JNI / JNA lubRuntime.exec()
. Jeśli nie masz nic przeciwko rozwiązaniu JNI / JNA, istnieje gethostname4j, który jest bardzo prosty i bardzo łatwy w użyciu.Przejdźmy do dwóch przykładów, jednego z Linuksa i jednego z Solaris, które pokazują, jak łatwo dostać się do sytuacji, w której nie można uzyskać nazwy komputera przy użyciu standardowych metod Java.
Przykład systemu Linux
W nowo utworzonym systemie, w którym host podczas instalacji został nazwany „chicago”, zmieniamy teraz tak zwaną nazwę hosta jądra:
Teraz nazwa hosta jądra to „dallas”, jak widać po poleceniu hostname:
Ale nadal mamy
Nie ma w tym żadnej błędnej konfiguracji. Oznacza to po prostu, że nazwa sieciowa hosta (a raczej nazwa interfejsu pętli zwrotnej) różni się od nazwy komputera hosta.
Teraz spróbuj wykonać,
InetAddress.getLocalHost().getHostName()
a wygeneruje wyjątek java.net.UnknownHostException. W zasadzie utknąłeś. Nie ma możliwości odzyskania wartości „dallas” ani wartości „chicago”.Przykład systemu Solaris
Poniższy przykład oparty jest na systemie Solaris 11.3.
Host został celowo skonfigurowany, aby nazwa pętli zwrotnej <> nazwa węzła.
Innymi słowy mamy:
oraz zawartość / etc / hosts:
a wynikiem polecenia nazwy hosta byłoby:
Podobnie jak w przykładzie z Linuksem wywołanie
InetAddress.getLocalHost().getHostName()
nie powiedzie sięTak jak w przykładzie z Linuksem, który utknął. Nie ma możliwości odzyskania wartości „dallas” ani wartości „chicago”.
Kiedy naprawdę będziesz miał z tym problem?
Bardzo często okazuje się, że
InetAddress.getLocalHost().getHostName()
rzeczywiście zwróci wartość równą nazwie komputera. Więc nie ma problemu (z wyjątkiem dodatkowego obciążenia związanego z rozpoznawaniem nazw).Problem pojawia się zwykle w środowiskach PaaS, w których istnieje różnica między nazwą komputera a nazwą interfejsu sprzężenia zwrotnego. Na przykład ludzie zgłaszają problemy w Amazon EC2.
Raporty o błędach / RFE
Trochę wyszukiwania ujawnia ten raport RFE: link1 , link2 . Jednak sądząc po komentarzach do tego raportu, wydaje się, że problem został w dużej mierze źle zrozumiany przez zespół JDK, więc jest mało prawdopodobne, że zostanie rozwiązany.
Podoba mi się porównanie w RFE z innymi językami programowania.
źródło
Zmienne środowiskowe mogą również stanowić użyteczny środek -
COMPUTERNAME
w systemie Windows,HOSTNAME
w większości nowoczesnych powłok Unix / Linux.Zobacz: https://stackoverflow.com/a/17956000/768795
Używam ich jako „dodatkowych” metod
InetAddress.getLocalHost().getHostName()
, ponieważ, jak zauważa kilka osób, ta funkcja nie działa we wszystkich środowiskach.Runtime.getRuntime().exec("hostname")
jest kolejnym możliwym dodatkiem. Na tym etapie nie korzystałem z niego.źródło
StringUtils
, zapewniono go w ramach projektu commons-lang Apache. Zaleca się korzystanie z niego lub czegoś podobnego.System.getenv("HOSTNAME")
wyszedł na zero na Macu przez Beanshell dla Javy, alePATH
został wyodrębniony. Mógłbym także zrobićecho $HOSTNAME
na komputerze Mac, tylko System.getenv („HOSTNAME”) wydaje się mieć problem. Dziwne.Najbardziej przenośnym sposobem uzyskania nazwy hosta bieżącego komputera w Javie jest:
źródło
Jeśli nie jesteś przeciwny używaniu zewnętrznej zależności od maven central, napisałem gethostname4j, aby rozwiązać ten problem dla siebie. Po prostu używa JNA do wywołania funkcji gethostname libc (lub pobiera ComputerName w systemie Windows) i zwraca ją jako ciąg znaków.
https://github.com/mattsheppard/gethostname4j
źródło
źródło
Wystarczy jedna linijka ... na wielu platformach (Windows-Linux-Unix-Mac (Unix)) [Zawsze działa, nie wymaga DNS]:
Jesteś skończony !!
źródło
InetAddress.getLocalHost (). GetHostName () to najlepsze wyjście z tych dwóch, ponieważ jest to najlepsza abstrakcja na poziomie programisty.
źródło