IT/개발

[Java] Server IP와 Client IP를 조회하는 방법 A to Z(feat. virtualbox host-only network ip)

알콩달콩아빠 2023. 8. 20. 17:29
728x90
반응형

Scheduler 기능을 구현하면서 IP 관련해서 처리할 필요가 생겼다.

스케줄러 기능을 구현해놓고 따로 처리하지 않을 시에는, 개발 PC들과 서버 PC 모두에서 스케줄러가 동작해 중복으로 작업이 처리될 것이기 때문이다.

 

다른 방법도 있겠지만, 나는 일단 IP로 처리하기로 했다.

스케줄러 동작 시에 현재 PC의 IP를 조회하고, IP가 서버 IP라면 스케줄러 기능이 동작하도록 말이다.

 

문제는 처음에 생각을 잘못해서 IP 조회를 Client IP를 획득하는 방식으로 했다는 것인데,

이 경우 모두 Localhost IP로 받아와지기 때문에 동일하게 처리된다.

 

또 다른 문제는, Client IP를 획득하려면 HttpServletRequest 의 데이터가 필요한데,

스케줄러로 동작 시에는 요청 시 필요한 데이터가 없기 때문에 No thread-bound request 에러가 발생한다.

@Autowired와 RequestContextHolder 등의 구글링으로 찾은 방식들로 해결해보려고 했으나 오류는 동일하게 발생했다.

 

그러던 중, 서버에서 동작해야 하는 건데 왜 클라이언트 IP를 따려고 하고 있는지 자각하게 되었고, 서버 IP를 조회하는 코드를 작성하여 원하는 스케줄러 기능을 구현했다. 문제는 또 있었지만...

 

 

 

[ 해결 방법 ]

 

1. 클라이언트 IP 조회

 

일단, 클라이언트 IP를 조회하는 코드부터 보겠다.

이는 사실 구글링을 통해 쉽게 발견하여 사용할 수 있다.

 

 

Java Client IP 가져오기

1. X-Forwarded-For X-Forwarded-For (XFF) 헤더는 HTTP 프록시나 로드 밸런서를 통해 웹 서버에 접속하는 클라이언트의 원 IP 주소를 식별하는 사실상의 표준 헤더다. 클라이언트와 서버 중간에서 트래픽이

dejavuhyo.github.io

 

위 블로그를 참고하여 해결하였다.

설명은 해당 블로그 글을 참고하면 상세히 알 수 있다.

간략히 설명하자면, 프록시 환경인 경우를 고려하여,

프록시 IP가 아닌 실제 클라이언트 IP를 반환하도록 구현한다고 생각하면 된다.

 

< 참고 >
- 내부 IP : getLocalAddr()
- 외부 IP : getRemoteAddr()

 

public String getClientIp(HttpServletRequest request) {
    ip = request.getHeader("X-Forwarded-For");

    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("HTTP_CLIENT_IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("X-Real-IP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("X-RealIP");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getHeader("REMOTE_ADDR");
    }
    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
        ip = request.getRemoteAddr();
    }
		
    return ip;
}

 

 

 

2. 서버 IP 조회

 

서버 IP를 조회하는 코드는 간단하다. 이것도 구글링을 통해 쉽게 구현할 수 있다.

 

public String getServerIp() {
    try{
        return InetAddress.getLocalHost().getHostAddress();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    }
    return null;
}

 

와 같이 작성하여 서버 IP를 쉽게 얻을 수 있다.

 

그러나...

 

언제나 의도대로 쉽게 되진 않는다.

코드를 서버 PC에 적용하였으나 스케줄러가 동작하지 않았다. 분명히 서버 IP를 적어 구분해주었는데도 말이다.

그래서 서버에서 IP를 출력해보니 192.168.56.1 이라는 IP가 나왔다.

그렇다! 이것은 virtualbox host-only network default ip인 것이다.

 

그렇다면, 이 IP는 걸러주고 실제 IP를 받아오도록 코드를 작성해야하는데,,,

다행히도 stackoverflow에 몇몇 예제가 있어서 이를 참고해 마침내 기능을 구현할 수 있었다.

아마 모든 사용에 부합하는 완벽한 코드는 아니겠지만 충분히 활용에 도움될 것이라 생각한다.

 

public String getServerIp() {
    try {
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while(interfaces.hasMoreElements()) {
            NetworkInterface ni = interfaces.nextElement();
            
            //MAC 주소 조회
            byte[] hardwareAddress = ni.getHardwareAddress();
            
            //Virtual Box의 MAC 주소 형태의 차이로 구별
            boolean virtual = false;
            if(hardwareAddress != null) {
                //hardwareAddress와 localIp 값을 각각 출력해보고
                //Virtual Box IP가 아닐 때의 MAC 주소를 아래 조건문을 통해 필터링
                if(hardwareAddress[0] != -44)
                    virtual = true;
            }
            if(virtual) continue;
				
            for(InterfaceAddress addr : ni.getInterfaceAddresses()) {
                InetAddress address = addr.getAddress();
                if(address.isSiteLocalAddress()) {
                    //주소 문자열에서 /가 나오는 것을 치환
                    String localIp = addr.getAddress().toString().replace("/", "");
                    return localIp;
                }
            }
        }
    } catch (SocketException e) {
        e.printStackTrace();
    }
		
    //Virtual Box가 없는 경우 위에서 걸리지 않는 것으로 보임
    //따라서, 위에서 반환되지 않은 경우
    //서버 IP를 조회하는 기존 코드를 추가 작성
    try {
        return InetAddress.getLocalHost().getHostAddress();
    } catch (UnknownHostException e) {
        e.printStackTrace();
    }
    
    return null;
}

 

이렇게 하면, 클라이언트 IP와 서버 IP를 각각 조회할 수 있다!

아직 많은 케이스가 검증되진 못했지만, 오류가 발생한다면 코드와 글을 지속적으로 업데이트할 예정이다.

 

출처 : [Java] Server IP와 Client IP를 조회하는 방법 A to Z(feat. virtualbox host-only network ip) (tistory.com)

728x90
반응형