Как получить локальное имя хоста, если оно неразрешимо через DNS в 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). См. Комментарии в примере кода.

Я бы хотел, чтобы был лучший способ.

Ответ 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, возможно, вам придется учитывать ее в некоторых случаях.

Ответ 3

В качестве альтернативы используйте JNA для вызова функции gethostname в unixes, избегая обратного поиска 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().

Ответ 4

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

Ответ 5

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

Ответ 6

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

Ответ 7

в Linux читайте

/proc/sys/kernel/hostname

Ответ 8

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

https://github.com/mattsheppard/gethostname4j

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