Как мне получить локальное имя хоста, если оно неразрешимо через DNS в Java?

#java #hostname

#java #имя хоста

Вопрос:

Это звучит как то, о чем следовало спрашивать раньше, и вроде как так и есть, но я хочу получить локальное имя хоста и IP-адреса компьютера, даже если это невозможно разрешить через DNS (в Java).

Я могу получить локальные IP-адреса без разрешения, выполнив итерацию NetworkInterfaces.getNetworkInterfaces() .

Любые ответы на этот вопрос, которые я нашел, указывают на использование getLocalHost ()

 InetAddress localhost = java.net.InetAddress.getLocalHost();
hostName = localhost.getHostName();
  

но это выдает UnknownHostException , если имя хоста невозможно разрешить через DNS.

Нет ли способа получить локальное имя хоста без поиска DNS, происходящего за кулисами?

редактировать: полученный IP-адрес равен 10.4.168.23 Исключение составляет java.net.UnknownHostException: cms1.companyname.com: cms1.companyname.com (имя хоста изменено для псевдоанонимности), и файл hosts не содержит имени хоста. Но он знает свое имя хоста, поэтому я не уверен, почему я не могу получить его без создания исключения.

Ответ №1:

Да, в Java должен быть способ получить имя хоста, не прибегая к поиску в службе имен, но, к сожалению, его нет.

Однако вы можете сделать что-то вроде этого:

 if (System.getProperty("os.name").startsWith("Windows")) {
    // Windows will always set the 'COMPUTERNAME' variable
    return System.getenv("COMPUTERNAME");
} else {
    // If it is not Windows then it is most likely a Unix-like operating system
    // such as Solaris, AIX, HP-UX, Linux or MacOS.

    // Most modern shells (such as Bash or derivatives) sets the 
    // HOSTNAME variable so lets try that first.
    String hostname = System.getenv("HOSTNAME");
    if (hostname != null) {
       return hostname;
    } else {

       // If the above returns null *and* the OS is Unix-like
       // then you can try an exec() and read the output from the 
       // 'hostname' command which exist on all types of Unix/Linux.

       // If you are an OS other than Unix/Linux then you would have 
       // to do something else. For example on OpenVMS you would find 
       // it like this from the shell:  F$GETSYI("NODENAME") 
       // which you would probably also have to find from within Java 
       // via an exec() call.

       // If you are on zOS then who knows ??

       // etc, etc
    }
}
  

и это даст вам на 100% то, что вы хотите на традиционных платформах Sun JDK (Windows, Solaris, Linux), но становится менее простым, если ваша ОС более требовательна (с точки зрения Java). Смотрите комментарии в примере кода.

Хотелось бы, чтобы был способ получше.

Комментарии:

1. К сожалению, я не получаю no HOSTNAME , когда Tomcat является сервисом rc.d под FreeBSD.

2. @lapo. Это не проблема Java. Вам нужно понять вашу оболочку: когда устанавливается HOSTNAME переменная среды? Вероятно, вы получите хороший ответ, если спросите на форуме Unix / Linux что-то вроде: «Переменная среды HOSTNAME не определена. Почему?» .

3. это не проблема Java, но доступность по умолчанию — это одно; если мне нужно изменить системные значения по умолчанию, я мог бы также правильно определить в 127.0.0.1 в /etc/host (что в любом случае является хорошим правилом). В итоге я использовал HOSTNAME else COMUTERNAME else getLocalHost() .

Ответ №2:

Этот вопрос старый, но, к сожалению, все еще актуален, поскольку получить имя хоста компьютера на Java все еще нетривиально. Вот мое решение с несколькими тестовыми запусками в разных системах:

 public static void main(String[] args) throws IOException {
        String OS = System.getProperty("os.name").toLowerCase();

        if (OS.indexOf("win") >= 0) {
            System.out.println("Windows computer name throguh env:""   System.getenv("COMPUTERNAME")   """);
            System.out.println("Windows computer name through exec:""   execReadToString("hostname")   """);
        } else {
            if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
                System.out.println("Linux computer name throguh env:""   System.getenv("HOSTNAME")   """);
                System.out.println("Linux computer name through exec:""   execReadToString("hostname")   """);
                System.out.println("Linux computer name through /etc/hostname:""   execReadToString("cat /etc/hostname")   """);
            }
        }
    }

    public static String execReadToString(String execCommand) throws IOException {
        Process proc = Runtime.getRuntime().exec(execCommand);
        try (InputStream stream = proc.getInputStream()) {
            try (Scanner s = new Scanner(stream).useDelimiter("\A")) {
                return s.hasNext() ? s.next() : "";
            }
        }
    }
  

Результаты для разных операционных систем:

openSUSE 13.1

 Linux computer name throguh env:"machinename"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:""
  

Ubuntu 14.04 LTS
Это довольно странно, поскольку echo $HOSTNAME возвращает правильное имя хоста, но System.getenv("HOSTNAME") этого не делает (это, однако, может быть проблемой только для моей среды):

 Linux computer name throguh env:"null"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:"machinename
"
  

Windows 7

 Windows computer name throguh env:"MACHINENAME"
Windows computer name through exec:"machinename
"
  

Имена компьютеров были заменены для (некоторой) анонимизации, но я сохранил заглавные буквы и структуру. Обратите внимание на дополнительный перевод строки при выполнении hostname , возможно, вам придется учитывать это в некоторых случаях.

Комментарии:

1. Я вижу ту же проблему в Ubuntu 14.04 с HOSTNAME переменной окружения. Оно не экспортируется в задачи, запускаемые командной оболочкой (bash). Выполнение export HOSTNAME решает проблему.

Ответ №3:

В качестве альтернативы, используйте JNA для вызова gethostname функции в unix, избегая обратного поиска DNS.

Некоторые примечания: в Linux, я полагаю, gethostname просто вызывает uname и анализирует выходные данные. В OS X ситуация более сложная, поскольку DNS может влиять на ваше имя хоста, но если отбросить эти побочные эффекты, это определенно то, что я получаю от hostname .

 import com.sun.jna.LastErrorException
import com.sun.jna.Library
import com.sun.jna.Native

...

private static final C c = (C) Native.loadLibrary("c", C.class);

private static interface C extends Library {
    public int gethostname(byte[] name, int size_t) throws LastErrorException;
}

public String getHostName() {
    byte[] hostname = new byte[256];
    c.gethostname(hostname, hostname.length)
    return Native.toString(hostname)
}
  

jna-platform.jar включает функции Win32, поэтому там это так же просто, как вызов Kernel32Util.getComputerName() .

Комментарии:

1. Лучший ответ, поскольку он не зависит от DNS.

Ответ №4:

Если вы получаете 127.0.0.1 в качестве IP-адреса, то вам может потребоваться найти файл hosts, специфичный для вашей операционной системы, и добавить в него сопоставление с вашим именем хоста.

Комментарии:

1. ОС знает имя хоста, так как когда я вызываю getLocalHost(), она выдает исключение, содержащее имя хоста. Я просто хочу иметь возможность получить это имя хоста без поиска.

2. Убедитесь, что ваше имя хоста не содержит символов подчеркивания. Если вы используете Windows, то это не помешает вам использовать символы подчеркивания в hostname, но это не работает с Java из-за строгой проверки разрешенных символов.

Ответ №5:

Это своего рода взлом. Но вы могли бы запустить новый процесс из Java и выполнить hostname команду. Чтение outputstream дочернего процесса даст вам имя локального хоста.

Комментарии:

1. Я тоже думал об этом, но надеялся на лучшее решение.

Ответ №6:

Java прочитает файл /etc / hosts, если DNS не настроен, или, скорее, это сделают соответствующие функции C.

Ответ №7:

в Linux прочитайте

 /proc/sys/kernel/hostname
  

Ответ №8:

Если вы не против использования внешней зависимости от maven central, я написал gethostname4j, чтобы решить эту проблему для себя. Он просто использует JNA для вызова функции gethostname в libc (или получает имя компьютера в Windows) и возвращает его вам в виде строки.

https://github.com/mattsheppard/gethostname4j

(Я думаю, это почти точно то, что предложил @danny-thomas, но, возможно, более удобно, если вы уже используете Maven 😉