source

Java에서 호스트 이름을 가져오는 권장 방법

factcode 2022. 8. 31. 22:33
반응형

Java에서 호스트 이름을 가져오는 권장 방법

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

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

InetAddress.getLocalHost().getHostName()

엄밀히 말하면, 당신도 전화할 수밖에 없어요.hostname(1)또는 - UNIX의 경우gethostname(2)컴퓨터 이름입니다.다음과 같은 IP 주소로 호스트 이름을 결정하려는 시도

InetAddress.getLocalHost().getHostName()

는 다음과 같은 상황에서 실패하게 되어 있습니다.

  • IP 주소가 어떤 이름으로도 확인되지 않을 수 있습니다.DNS 설정, 시스템 설정, 프로바이더 설정 등이 원인일 수 있습니다.
  • DNS 의 이름에는, CNAME 이라고 하는 에일리어스를 다수 포함할 수 있습니다.이러한 문제는 이름에서 주소로 한 방향으로만 해결할 수 있습니다.그 반대 방향은 애매하다.어느 것이 공식 이름입니까?
  • 호스트에는 다양한 IP 주소를 사용할 수 있으며 각 주소에는 다양한 이름을 사용할 수 있습니다.일반적인 경우는 1개의 이더넷포트가 복수의 「논리적인」IP 주소를 가지는 경우와 컴퓨터에 복수의 이더넷 포토를 가지는 경우입니다.IP 를 공유하는지, 다른 IP 를 가지는지를 설정할 수 있습니다.이를 멀티홈이라고 합니다.
  • DNS 의 1 개의 이름을 복수의 IP 주소로 확인할 수 있습니다.또, 이러한 주소가 모두 같은 컴퓨터에 있는 것은 아닙니다(용례:심플한 형태의 로드밸런싱)
  • 다이나믹 IP 주소에 대해서는 언급하지 말아 주세요.

또, IP 주소의 이름과 호스트명(호스트명)을 혼동하지 말아 주세요.은유를 통해 더 명확해질 수 있습니다.

런던이라는 대도시(서버)가 있다.도시의 성벽 안에서는 많은 사업이 일어난다.이 도시에는 여러 개의 게이트(IP 주소)가 있습니다.각 게이트에는 이름("노스 게이트", "리버 게이트", "사우스햄튼 게이트...")이 있지만, 게이트의 이름은 도시의 이름이 아닙니다.또한 당신은 대문이라는 이름을 사용하여 도시의 이름을 추론할 수 없다 - "북문"은 하나의 도시가 아니라 큰 도시의 절반을 차지할 것이다.하지만 낯선 사람(IP 패킷)이 강을 따라 걸으며 현지인에게 묻습니다. "저는 이상한 주소를 가지고 있습니다: '리버게이트, 두 번째 왼쪽, 세 번째 집'입니다."도와주실 수 있나요?현지인은 "물론 올바른 길을 가고 있습니다.그냥 가면 30분 안에 목적지에 도착합니다."라고 말한다.

이게 거의 그걸 설명해 주는 것 같아요.

좋은 소식은 다음과 같습니다.통상, 실제의 호스트명은 필요 없습니다.대부분의 경우, 이 호스트상에서 IP 주소로 해결되는 이름은 모두 사용할 수 있습니다.(낯선 사람은 노스게이트를 통해 도시에 들어올 수 있지만 도움이 되는 현지인이 "두 번째 왼쪽" 부분을 번역합니다.)

나머지 코너 케이스에서는 이 설정의 최종 소스(C 함수)를 사용해야 합니다.gethostname(2)이 함수는 프로그램에서도 호출됩니다.hostname.

InetAddress.getLocalHost().getHostName()휴대성이 향상되었습니다.

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

SO에 관한 기타 몇 가지 답변은 다음과 같습니다.

편집: A을 참조하십시오.H.의 답변 또는 Arnout Engelen의 답변으로 상황에 따라 이것이 예상대로 작동하지 않는 이유에 대한 자세한 내용은 다음과 같습니다.특별히 휴대성을 요청하신 분에 대한 답변으로, 저는 여전히 생각합니다.getHostName()괜찮지만 고려해야 할 몇 가지 좋은 점들이 떠오릅니다.

다른 사람들이 지적했듯이 DNS 해결에 기반한 호스트 이름을 얻는 것은 신뢰할 수 없습니다.

아쉽게도 이 질문은 2018년에도 유효하기 때문에 네트워크에 의존하지 않는 솔루션을 공유하여 여러 시스템에서 테스트를 진행하고자 합니다.

다음 코드는 다음을 시도합니다.

  • Windows 의 경우

    1. 를 참조해 주세요.COMPUTERNAME환경변수System.getenv().

    2. 실행hostname.exe반응도 읽어보고

  • Linux의 경우

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

Open Suse 13.1

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

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

편집: 레골라스108에 따르면System.getenv("HOSTNAME")를 실행하면 Ubuntu 14.04에서 동작합니다.export HOSTNAMEJava 코드를 실행하기 전에.

윈도 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()(Nick이 설명한 바와 같이) 더 낫지만, 여전히 매우 좋지는 않습니다.

1 개의 호스트는, 복수의 다른 호스트명으로 알 수 있습니다.일반적으로 특정 컨텍스트에서 호스트의 호스트 이름을 찾습니다.

예를 들어 웹 응용 프로그램에서 현재 처리 중인 요청을 발행한 사용자가 사용한 호스트 이름을 찾을 수 있습니다.웹 응용 프로그램에 사용하는 프레임워크에 따라 최적의 검색 방법이 달라집니다.

다른 종류의 인터넷 접속 서비스에서는, 「외부」로부터 서비스를 이용할 수 있는 호스트명이 필요합니다.프록시, 방화벽 등으로 인해 서비스가 설치되어 있는 머신의 호스트명이 아닐 수 있습니다.이것에 대해서는, 적절한 디폴트를 설정하려고 할 수도 있습니다만, 반드시 이것을 인스톨 하는 유저에 대해서 설정할 수 있도록 해 주세요.

이 주제는 이미 답변이 되었지만, 더 할 말이 있습니다.

우선, 분명히 여기에 몇 가지 정의가 필요합니다.InetAddress.getLocalHost().getHostName()에, 네트워크의 관점에서 본 호스트의 이름을 나타냅니다.이 접근방식의 문제는 다른 답변에 잘 설명되어 있습니다.대부분 DNS 룩업이 필요하고, 호스트에 복수의 네트워크 인터페이스가 있는 경우는 애매하며, 경우에 따라서는 완전히 실패하는 경우가 있습니다(아래를 참조.

그러나 어떤 OS에도 다른 이름이 있습니다.네트워크가 초기화되기 훨씬 전에 부트 프로세스 초기에 정의되는 호스트의 이름입니다.Windows 에서는 이것을 컴퓨터명, Linux 에서는 커널 호스트명, Solaris 에서는 nodename 이라고 부릅니다.컴퓨터명이라는 단어가 제일 좋기 때문에 앞으로는 그 단어를 사용할 거예요.

컴퓨터 이름 찾기

  • Linux/Unix의 경우 컴퓨터 이름은 C 함수에서 얻을 수 있습니다.gethostname(), 또는hostname명령어를 셸로부터의 명령어HOSTNAMEBash 유사 셸의 환경변수는 Bash-like shell 입니다.

  • 윈도우즈에서 컴퓨터 이름은 환경 변수에서 얻은 이름입니다.COMPUTERNAME또는 Win32GetComputerName기능.

Java는 제가 'computername'이라고 정의한 것을 얻을 방법이 없습니다.물론 Windows 호출과 같은 다른 응답에 설명된 해결 방법이 있습니다.System.getenv("COMPUTERNAME")단, Unix/Linux에서는 JNI/JNA 또는Runtime.exec()JNI/JNA 솔루션을 사용해도 괜찮으시다면 gethostname4j가 있습니다.gethostname4j는 매우 간단하고 사용하기 쉽습니다.

다음으로 Linux와 Solaris의 두 가지 예를 들어보겠습니다.이 예에서는 표준 Java 방법을 사용하여 컴퓨터 이름을 쉽게 얻을 수 없는 상황을 보여줍니다.

Linux 예시

새로 생성된 시스템에서 설치 중 호스트의 이름이 'chicago'로 지정되었습니다. 이제 커널 호스트 이름을 변경합니다.

$ hostnamectl --static set-hostname dallas

여기서 hostname 명령에서 알 수 있듯이 커널 호스트 이름은 '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의 예

다음 예시는 Solaris 11.3에 기초하고 있습니다.

호스트는 루프백명<>노드네임이 되도록 의도적으로 설정되어 있습니다.

즉, 다음과 같은 이점이 있습니다.

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

및 /etc/filename의 내용은 다음과 같습니다.

:1 chicago localhost
127.0.0.1 chicago localhost loghost

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

$ hostname
dallas

Linux 의 예와 같이, 에의 호출을 실시합니다.InetAddress.getLocalHost().getHostName()에 실패하다

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

Linux 의 예와 같이, 지금 막히고 있습니다.dallas 값도 chicago 값도 검색할 방법이 없습니다.

당신은 언제 이 일로 정말 고생할 건가요?

자주 보게 될 것이다.InetAddress.getLocalHost().getHostName()는 컴퓨터 이름과 동일한 값을 반환합니다.따라서 문제 없습니다(이름 해결에 따른 추가 오버헤드 제외).

이 문제는 일반적으로 컴퓨터 이름과 루프백인터페이스 이름이 다른 PaaS 환경에서 발생합니다.예를 들어 사람들은 아마존 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;

1개의 라이너만으로 크로스 플랫폼(Windows-Linux-Unix-Mac(Unix)) [항상 기능하며 DNS는 필요 없습니다]:

String hostname = new BufferedReader(
    new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))
   .readLine();

끝났어!!

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

maven central로부터의 외부 의존을 사용하는 것에 반대하지 않는다면, 이 문제를 스스로 해결하기 위해 gethostname4j를 작성했습니다.JNA를 사용하여 libc의 gethostname 함수를 호출(또는 Windows에서 ComputerName을 취득)하여 문자열로 반환합니다.

https://github.com/mattsheppard/gethostname4j

hostName == null;
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
{
    while (interfaces.hasMoreElements()) {
        NetworkInterface nic = interfaces.nextElement();
        Enumeration<InetAddress> addresses = nic.getInetAddresses();
        while (hostName == null && addresses.hasMoreElements()) {
            InetAddress address = addresses.nextElement();
            if (!address.isLoopbackAddress()) {
                hostName = address.getHostName();
            }
        }
    }
}

InetAddress.getLocalHost().getHostName()은 개발자 수준에서 최적의 추상화이기 때문에 둘 중 가장 좋은 방법입니다.

언급URL : https://stackoverflow.com/questions/7348711/recommended-way-to-get-hostname-in-java

반응형