Какой из следующих способов является лучшим и наиболее переносимым способом получения имени хоста текущего компьютера в Java?
Runtime.getRuntime().exec("hostname")
против
InetAddress.getLocalHost().getHostName()
Какой из следующих способов является лучшим и наиболее переносимым способом получения имени хоста текущего компьютера в Java?
Runtime.getRuntime().exec("hostname")
против
InetAddress.getLocalHost().getHostName()
Ответы:
Строго говоря, у вас нет выбора, кроме как позвонить
hostname(1)
или - в Unixgethostname(2)
. Это имя вашего компьютера. Любая попытка определить имя хоста по IP-адресу, подобному этомуобязательно потерпит неудачу в некоторых обстоятельствах:
Также не следует путать имя IP-адреса с именем хоста (hostname). Метафора может прояснить это:
Это иллюстрирует это в значительной степени, я думаю.
Хорошая новость: реальное имя хоста обычно не требуется. В большинстве случаев подойдет любое имя, которое разрешается в IP-адрес на этом хосте. (Незнакомец может войти в город через Нортгейт, но полезные местные жители переводят часть «2-й левый».)
Если в остальных случаях угловых вы должны использовать окончательный источник этой настройки конфигурации - которая является функцией C
gethostname(2)
. Эта функция также вызывается программойhostname
.источник
InetAddress.getLocalHost().getHostName()
это более портативный способ.exec("hostname")
фактически вызывает операционную систему для выполненияhostname
команды.Вот пара других связанных ответов на SO:
РЕДАКТИРОВАТЬ: Вам следует взглянуть на ответ AH или ответ Arnout Engelen, чтобы узнать, почему это может работать не так, как ожидалось, в зависимости от вашей ситуации. В качестве ответа для этого человека, который специально попросил портативное устройство, я все еще думаю, что
getHostName()
это хорошо, но они поднимают некоторые хорошие моменты, которые следует учитывать.источник
InetAddress.getLocalHost()
в некоторых случаях возвращает устройство обратной петли. В этом случаеgetHostName()
возвращает «localhost», что не очень полезно.Как уже отмечалось, получение имени хоста на основе разрешения DNS ненадежно.
Поскольку этот вопрос, к сожалению, по-прежнему актуален в 2018 году , я хотел бы поделиться с вами своим независимым от сети решением, проведя несколько тестовых прогонов на разных системах.
Следующий код пытается сделать следующее:
На винде
Прочитайте
COMPUTERNAME
переменную среды черезSystem.getenv()
.Выполнить
hostname.exe
и прочитать ответВ линуксе
Прочитайте
HOSTNAME
переменную среды черезSystem.getenv()
Выполнить
hostname
и прочитать ответЧитать
/etc/hostname
(для этого я выполняю,cat
так как фрагмент уже содержит код для выполнения и чтения. Хотя лучше просто прочитать файл).Код:
Результаты для разных операционных систем:
macOS 10.13.2
OpenSuse 13.1
Ubuntu 14.04 LTS Это странно, так как
echo $HOSTNAME
возвращает правильное имя хоста, ноSystem.getenv("HOSTNAME")
не делает:РЕДАКТИРОВАТЬ: Согласно legolas108 ,
System.getenv("HOSTNAME")
работает на Ubuntu 14.04, если вы запускаетеexport HOSTNAME
до выполнения кода Java.Windows 7
Windows 10
Названия машин были заменены, но я сохранил капитализацию и структуру. Обратите внимание на дополнительный символ новой строки при выполнении
hostname
, возможно, вам придется принять его во внимание в некоторых случаях.источник
export HOSTNAME
до запуска Java-кода на Ubuntu 14.04 LTS также возвращалиSystem.getenv("HOSTNAME")
.export HOSTNAME
для Java использовать его? Я думал, что это должен быть env var по умолчанию, как PATH.\A
разделитель - это просто хак для чтения всего InputStream с помощью aScanner
.InetAddress.getLocalHost().getHostName()
лучше (как объяснил Ник), но все же не очень хорошоОдин хост может быть известен под разными именами хоста. Обычно вы будете искать имя вашего хоста в определенном контексте.
Например, в веб-приложении вы можете искать имя хоста, используемое тем, кто отправил запрос, который вы сейчас обрабатываете. Как лучше всего это найти, зависит от того, какую платформу вы используете для своего веб-приложения.
В какой-либо другой интернет-службе вам нужно, чтобы имя хоста, через которое доступна ваша служба, было «извне». Из-за прокси-серверов, брандмауэров и т. Д. Это может даже не быть именем хоста на машине, на которой установлена ваша служба - вы можете попытаться найти разумное значение по умолчанию, но вам обязательно следует настроить его для любого, кто его устанавливает.
источник
Хотя на эту тему уже ответили, есть еще что сказать.
Прежде всего: очевидно, нам нужны некоторые определения здесь. Это
InetAddress.getLocalHost().getHostName()
дает вам имя хоста с точки зрения сети . Проблемы с этим подходом хорошо задокументированы в других ответах: он часто требует поиска DNS, он неоднозначен, если у хоста несколько сетевых интерфейсов, и иногда он просто выходит из строя (см. Ниже).Но в любой ОС есть и другое имя. Имя хоста, которое определяется очень рано в процессе загрузки, задолго до инициализации сети. Windows называет это как имя компьютера , Linux называет его именем хоста ядра, а Solaris использует слово nodename . Мне больше всего нравится слово computername , так что теперь я буду использовать это слово.
Нахождение имени компьютера
В Linux / Unix имя компьютера - это то, что вы получаете из функции C
gethostname()
илиhostname
команды из оболочки илиHOSTNAME
переменной среды в оболочках, подобных Bash.В Windows имя компьютера - это то, что вы получаете из переменной среды
COMPUTERNAME
илиGetComputerName
функции Win32 .У Java нет способа получить то, что я определил как «имя компьютера». Конечно, есть обходные пути, как описано в других ответах, например, для вызовов Windows
System.getenv("COMPUTERNAME")
, но в Unix / Linux нет хорошего обходного пути, не прибегая к JNI / JNA илиRuntime.exec()
. Если вы не возражаете против решения JNI / JNA, то есть gethostname4j, который очень прост и очень прост в использовании.Давайте перейдем к двум примерам, одному из Linux и одному из Solaris, которые демонстрируют, как вы легко можете попасть в ситуацию, когда вы не можете получить имя компьютера, используя стандартные методы Java.
Пример Linux
В недавно созданной системе, где хост во время установки был назван 'chicago', мы теперь изменим так называемое имя хоста ядра:
Теперь имя хоста ядра 'dallas', как видно из команды hostname:
Но у нас все еще есть
Там нет неправильной конфигурации в этом. Это просто означает, что сетевое имя хоста (или, скорее, имя интерфейса обратной связи) отличается от имени компьютера хоста.
Теперь попробуйте выполнить,
InetAddress.getLocalHost().getHostName()
и он выдаст исключение java.net.UnknownHostException. Вы в основном застряли. Нет способа получить ни значение «Даллас», ни значение «Чикаго».Пример соляриса
Пример ниже основан на Solaris 11.3.
Хост специально настроен так, чтобы имя петлевого имени <> имя узла.
Другими словами, мы имеем:
и содержимое / etc / hosts:
и результат команды hostname будет:
Как и в примере с Linux, при вызове
InetAddress.getLocalHost().getHostName()
произойдет сбойТочно так же, как пример с Linux, вы застряли. Нет способа получить ни значение «Даллас», ни значение «Чикаго».
Когда вы действительно будете бороться с этим?
Очень часто вы обнаружите, что
InetAddress.getLocalHost().getHostName()
действительно вернет значение, равное имени компьютера. Так что проблем нет (за исключением дополнительных накладных расходов на разрешение имен).Проблема обычно возникает в средах PaaS, где есть разница между именем компьютера и именем интерфейса обратной связи. Например, люди сообщают о проблемах в Amazon EC2.
Отчеты об ошибках / RFE
Немного поиска показывает этот отчет RFE: link1 , link2 . Однако, судя по комментариям к этому отчету, команда JDK, по-видимому, в значительной степени неправильно поняла проблему, поэтому вряд ли она будет решена.
Мне нравится сравнение в RFE с другими языками программирования.
источник
Переменные среды также могут быть полезны -
COMPUTERNAME
в Windows,HOSTNAME
в большинстве современных оболочек Unix / Linux.См .: https://stackoverflow.com/a/17956000/768795.
Я использую их как «дополнительные» методы
InetAddress.getLocalHost().getHostName()
, поскольку, как отмечают несколько человек, эта функция работает не во всех средах.Runtime.getRuntime().exec("hostname")
еще одно возможное дополнение. На данном этапе я не использовал его.источник
StringUtils
, это предусмотрено проектом Apache commons-lang. Настоятельно рекомендуется использовать его или что-то подобное.System.getenv("HOSTNAME")
вышел нулевым на Mac через Beanshell для Java, ноPATH
был извлечен нормально. Я мог бы также сделатьecho $HOSTNAME
на Mac, просто System.getenv ("HOSTNAME"), кажется, проблема. Странный.Наиболее переносимый способ получения имени хоста текущего компьютера в Java заключается в следующем:
источник
Если вы не против использования внешней зависимости от maven central, я написал gethostname4j, чтобы решить эту проблему для себя. Он просто использует JNA для вызова функции gethostname в libc (или получает имя_компьютера в Windows) и возвращает его вам в виде строки.
https://github.com/mattsheppard/gethostname4j
источник
источник
Просто одна строка ... кросс-платформенная (Windows-Linux-Unix-Mac (Unix)) [Всегда работает, DNS не требуется]:
Вы сделали !!
источник
InetAddress.getLocalHost (). GetHostName () - лучший выход из двух, поскольку это лучшая абстракция на уровне разработчика.
источник