[java] Java로 호스트 이름을 얻는 권장 방법

다음 중 Java로 현재 컴퓨터의 호스트 이름을 얻는 가장 쉽고 이식 가능한 방법은 무엇입니까?

Runtime.getRuntime().exec("hostname")

vs

InetAddress.getLocalHost().getHostName()



답변

엄밀히 말하면- hostname(1)또는 유닉스를 호출하는 것 외에는 선택의 여지가 없습니다 gethostname(2). 이것은 컴퓨터의 이름입니다. 이와 같은 IP 주소로 호스트 이름을 확인하려는 시도

InetAddress.getLocalHost().getHostName()

어떤 상황에서는 실패 할 것입니다 :

  • IP 주소는 어떤 이름으로도 해석되지 않을 수 있습니다. 잘못된 DNS 설정, 잘못된 시스템 설정 또는 잘못된 제공자 설정이 그 원인 일 수 있습니다.
  • DNS의 이름에는 CNAME이라는 많은 별칭이있을 수 있습니다. 이것은 한 방향으로 만 해결할 수 있습니다 : 이름에서 주소로. 반대 방향이 모호합니다. “공식”이름은 무엇입니까?
  • 호스트는 다른 IP 주소를 가질 수 있으며 각 주소는 다른 이름을 가질 수 있습니다. 두 가지 일반적인 경우는 다음과 같습니다. 하나의 이더넷 포트에 여러 “논리적”IP 주소가 있거나 컴퓨터에 여러 개의 이더넷 포트가 있습니다. IP를 공유하는지 또는 다른 IP를 가지고 있는지 구성 할 수 있습니다. 이것을 “멀티 홈”이라고합니다.
  • DNS에서 하나의 이름은 여러 IP 주소로 해석 될 수 있습니다. 이러한 주소가 모두 같은 컴퓨터에 있어야하는 것은 아닙니다! (사용 사례 : 간단한 형태의로드 밸런싱)
  • 동적 IP 주소에 대해서도 이야기하지 마십시오.

또한 IP 주소 이름과 호스트 이름 (호스트 이름)을 혼동하지 마십시오. 은유가 더 명확하게 만들 수 있습니다.

“런던”이라는 대도시 (서버)가 있습니다. 성벽 안에서 많은 사업이 일어납니다. 도시에는 여러 개의 게이트 (IP 주소)가 있습니다. 각 게이트에는 이름 ( “North Gate”, “River Gate”, “Southampton Gate”…)이 있지만 게이트 이름은 도시 이름이 아닙니다. 또한 게이트 이름을 사용하여 도시 이름을 추론 할 수 없습니다. “North Gate”는 한 도시가 아니라 큰 도시의 절반을 차지합니다. 그러나 낯선 사람 (IP 패킷)이 강을 따라 걸어 가서 현지인에게 다음과 같이 묻습니다. 현지인은 “물론 올바른 길을 가고 있습니다. 30 분 안에 목적지에 도착할 것입니다.”라고 말합니다.

이것은 내가 생각하는 것을 거의 보여줍니다.

좋은 소식은 : 실제 호스트 이름은 일반적으로 필요하지 않습니다. 대부분의 경우이 호스트의 IP 주소로 확인되는 모든 이름이 사용됩니다. (이방인은 노스 게이트를 통해 도시로 들어올 수 있지만 도움이되는 지역 주민들은 “왼쪽 2 번째”부분을 번역합니다.)

나머지 코너 의 경우이 구성 설정 의 최종 소스 (C 기능)를 사용해야합니다 gethostname(2). 이 기능은 또한 프로그램에 의해 호출됩니다 hostname.


답변

InetAddress.getLocalHost().getHostName() 더 휴대하기 쉬운 방법입니다.

exec("hostname")실제로 운영 체제를 호출하여 hostname명령 을 실행합니다 .

SO에 대한 몇 가지 다른 답변이 있습니다.

편집 : 당신은 AH의 대답을 봐야합니다 상황에 따라 또는 Arnout Engelen의 답변 을 예상대로 작동하지 않는 이유에 대한 자세한 내용을 살펴보십시오. 특별히 휴대용을 요청한이 사람에 대한 답변으로, 나는 여전히 getHostName()괜찮다고 생각 하지만 고려해야 할 몇 가지 좋은 점을 제시합니다.


답변

다른 사람들이 지적했듯이 DNS 확인을 기반으로 호스트 이름을 얻는 것은 신뢰할 수 없습니다.

이 질문은 불행히도 2018 년 에도 여전히 관련이 있기 때문에 다른 시스템에서 일부 테스트를 실행하여 네트워크 독립적 인 솔루션을 공유하고 싶습니다.

다음 코드는 다음을 수행하려고 시도합니다.

  • Windows에서

    1. COMPUTERNAME통해 환경 변수를 읽습니다 System.getenv().

    2. hostname.exe응답을 실행 하고 읽습니다.

  • 리눅스에서

    1. HOSTNAME통해 환경 변수를 읽으십시오System.getenv()

    2. hostname응답을 실행 하고 읽습니다.

    3. 읽기 /etc/hostname(이 cat코드는 이미 실행하고 읽을 코드가 포함되어 있기 때문에 실행 중입니다. 파일을 읽는 것이 더 좋을 것입니다).

코드:

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() : "";
    }
}

다른 운영 체제에 대한 결과 :

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:""

오픈 수세 13.1

Unix-like computer name through env:"machinename"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:""

우분투 14.04 LTS
이것은 echo $HOSTNAME올바른 호스트 이름을 반환하기 때문에 다소 이상 하지만 다음과 같은 System.getenv("HOSTNAME")것은 아닙니다.

Unix-like computer name through env:"null"
Unix-like computer name through exec:"machinename
"
Unix-like computer name through /etc/hostname:"machinename
"

편집 : legolas108 에 따르면 Java 코드 System.getenv("HOSTNAME")를 실행 export HOSTNAME하기 전에 실행 하면 Ubuntu 14.04 에서 작동 합니다.

윈도우 7

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

윈도우 10

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

기계 이름이 바뀌었지만 대문자와 구조를 유지했습니다. 를 실행할 때 추가 줄 바꿈을 참고하십시오 hostname.


답변

InetAddress.getLocalHost().getHostName() (닉이 설명한대로) 더 좋지만 여전히 그리 좋지는 않습니다.

하나의 호스트는 여러 다른 호스트 이름으로 알려질 수 있습니다. 일반적으로 호스트는 특정 컨텍스트에서 호스트 이름을 찾습니다.

예를 들어, 웹 애플리케이션에서 현재 처리중인 요청을 발행 한 사람이 사용한 호스트 이름을 찾고있을 수 있습니다. 가장 적합한 방법은 웹 응용 프로그램에 사용중인 프레임 워크에 따라 다릅니다.

다른 종류의 인터넷 연결 서비스에서는 ‘외부’에서 서비스를 사용할 수있는 호스트 이름이 필요합니다. 프록시, 방화벽 등으로 인해 이것은 서비스가 설치된 시스템의 호스트 이름이 아닐 수도 있습니다. 합리적인 기본값을 설정하려고 시도 할 수 있지만이를 설치하는 사람은 반드시 구성 할 수 있어야합니다.


답변

이 주제에 대해 이미 답변을 받았지만 더 많은 할 말이 있습니다.

우선 : 분명히 여기에 몇 가지 정의가 필요합니다. 는 InetAddress.getLocalHost().getHostName()당신에게 호스트의 이름을 제공 네트워크 관점에서 본 . 이 접근 방식의 문제점은 다른 답변에 잘 설명되어 있습니다. 종종 DNS 조회가 필요합니다. 호스트에 여러 개의 네트워크 인터페이스가 있고 때로는 실패 할 경우 모호합니다 (아래 참조).

그러나 모든 OS에는 다른 이름도 있습니다. 네트워크가 초기화되기 훨씬 전에 부트 프로세스 초기에 정의되는 호스트 이름. Windows는이를 컴퓨터 이름 으로 지칭하고 , Linux는이를 커널 호스트 이름이라고 하며 Solaris는 단어 nodename을 사용합니다 . 나는 computername 이라는 단어를 가장 좋아 하므로 앞으로 그 단어를 사용할 것입니다.

컴퓨터 이름 찾기

  • 리눅스 / 유닉스 컴퓨터 이름을 사용하면 C 함수에서 무엇을 얻을 gethostname(), 또는 hostname쉘 또는에서 명령 HOSTNAME쉘 강타 – 같은 환경 변수.

  • Windows에서 컴퓨터 이름은 환경 변수 COMPUTERNAME또는 Win32 GetComputerName기능 에서 얻는 것입니다 .

Java는 ‘computername’으로 정의한 것을 얻을 수있는 방법이 없습니다. 물론, Windows calling와 같은 다른 답변에 설명 된 해결 방법이 System.getenv("COMPUTERNAME")있지만 Unix / Linux에서는 JNI / JNA 또는에 의지하지 않으면 좋은 해결 방법이 없습니다 Runtime.exec(). JNI / JNA 솔루션이 마음에 들지 않으면 gethostname4j 가 있으며 간단하고 사용하기 쉽습니다.

표준 Java 메소드를 사용하여 컴퓨터 이름을 얻을 수없는 상황에 쉽게 도달 할 수있는 방법을 보여주는 Linux 및 Solaris의 두 가지 예를 살펴 보겠습니다.

리눅스 예

설치 중 호스트 이름이 ‘chicago’인 새로 작성된 시스템에서 이제 커널 호스트 이름을 변경합니다.

$ hostnamectl --static set-hostname dallas

이제 호스트 이름 명령에서 알 수 있듯이 커널 호스트 이름은 ‘dallas’입니다.

$ hostname
dallas

그러나 우리는 여전히

$ cat /etc/hosts
127.0.0.1   localhost
127.0.0.1   chicago

이 구성에는 잘못된 구성이 없습니다. 호스트의 네트워크 이름 (또는 루프백 인터페이스의 이름)이 호스트의 컴퓨터 이름과 다르다는 것을 의미합니다.

이제 실행을 시도 InetAddress.getLocalHost().getHostName() 하면 java.net.UnknownHostException이 발생합니다. 당신은 기본적으로 붙어 있습니다. ‘dallas’또는 ‘chicago’값을 검색 할 방법이 없습니다.

솔라리스 예제

아래 예는 Solaris 11.3을 기반으로합니다.

루프백 이름 <> nodename이되도록 호스트가 일부러 구성되었습니다.

다시 말해 우리는

$ svccfg -s system/identity:node listprop config
...
...
config/loopback             astring        chicago
config/nodename             astring        dallas

/ etc / hosts의 내용 :

:1 chicago localhost
127.0.0.1 chicago localhost loghost

hostname 명령의 결과는 다음과 같습니다.

$ hostname
dallas

리눅스 예제에서와 마찬가지로 호출 InetAddress.getLocalHost().getHostName()은 실패합니다.

java.net.UnknownHostException: dallas:  dallas: node name or service name not known

Linux 예제와 마찬가지로 이제 막혔습니다. ‘dallas’또는 ‘chicago’값을 검색 할 방법이 없습니다.

당신은 언제 정말로 이것과 싸울 것입니까?

종종 InetAddress.getLocalHost().getHostName()컴퓨터 이름과 같은 값을 반환 한다는 것을 알게 될 것입니다. 따라서 문제가 없습니다 (이름 확인의 추가 오버 헤드 제외).

이 문제는 일반적으로 컴퓨터 이름과 루프백 인터페이스 이름이 다른 PaaS 환경에서 발생합니다. 예를 들어 사람들은 Amazon EC2에서 문제를보고합니다.

버그 / RFE 보고서

약간의 검색으로이 RFE 보고서가 표시됩니다 ( link1 , link2) . 그러나 해당 보고서에 대한 의견을 바탕으로 JDK 팀은이 문제를 크게 오해 한 것으로 보이므로 해결되지 않을 것입니다.

RFE에서 다른 프로그래밍 언어와 비교하는 것이 좋습니다.


답변

환경 변수는 COMPUTERNAMEWindows, HOSTNAME대부분의 최신 Unix / Linux 쉘 에서 유용한 수단을 제공 할 수도 있습니다 .

참조 : https://stackoverflow.com/a/17956000/768795

InetAddress.getLocalHost().getHostName()여러 사람들이 지적했듯이 모든 환경에서 해당 기능이 작동하지 않기 때문에 이를 “보완”방법으로 사용 하고 있습니다.

Runtime.getRuntime().exec("hostname")또 다른 가능한 보충제입니다. 이 단계에서는 사용하지 않았습니다.

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;


답변

Java로 현재 컴퓨터의 호스트 이름을 얻는 가장 쉬운 방법은 다음과 같습니다.

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);
    }
}