로그인

Language :
제목Java RMI
글쓴이이지섭작성일2018-01-18수정일2024-08-09조회수6982

Java RMI (Remote Method Invocation) 는 분산 환경에서 원격 객체를 통하여 서버, 클라이언트 간에 통신하는 기능을 제공해 준다.

 

RMI 서비스는 두 개의 포트로 서버와 클라이언트 간에 통신한다.

 

하나는 RMI Registry 가 통신하는 포트이며,

하나는 Remote Object 가 통신하는 포트이다.

 

RMI Registry 는 기본 포트가 1099 이며,

Remote Object 는 지정하지 않는 경우 임의의 포트로 연결을 맺어 통신한다.

 

때문에 같은 서버(PC) 간에 통신할 때는 무리가 없겠으나,

다른 서버(PC) 간에 통신할 때는 포트가 열려있지 않아서 거의 서비스가 불가능하다고 볼 수도 있다.

 

포트를 지정하고, 서버 측에서 TCP 의 두 포트를 개방해야 서비스가 가능해진다.

 

 

원격 객체 (Remote Object) 는 java.rmi.Remote 객체를 상속하는 Java Interface 로 생성하며,

서버와 클라이언트는 RMI Registry 를 통하여 이 Interface 를 찾고 통신하게 된다.

 

이 원격 객체의 interface 를 구현(implements)하는 것은 서버 프로그램이다.

 

RMI Registry 는 백그라운드로 프로그램을 실행시키며 이 때 포트를 지정할 수 있다.

 

서버는 원격 객체(Remote Object)를 배포(export)할 때 또 그 포트를 지정하고,

RMI Registry 에 이 객체를 bind 한다.

 

서버와 클라이언트는 RMI Registry 를 찾을(getRegistry) 때 또 그 포트를 지정한다.

 

[프로그램 소스]

원격 개체 Interface

 : Hello.java

  - java.rmi.Remote 클래스를 상속한다.

package example.hello;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
    String sayHello() throws RemoteException;
}

 

서버 측 프로그램

 : Server.java

  - 원격 객체 (Remote Object) 는 2002 포트로 통신하며,

  - RMI Registry 는 2000 포트에서 찾도록 하였다.

package example.hello;

import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
        
public class Server implements Hello {

    public Server() {}

    public String sayHello() {
        return "Hello, world!";
    }
        
    public static void main(String args[]) {

        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        
        try {
            Server obj = new Server();
            Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 2002);

            // Bind the remote object's stub in the registry
            Registry registry = LocateRegistry.getRegistry(2000);
            registry.bind("Hello", stub);

            System.err.println("Server ready");
        } catch (Exception e) {
            System.err.println("Server exception: " + e.toString());
            e.printStackTrace();
        }
    }
}

 

클라이언트 측 프로그램

 : Client.java

  - 서버 IP 를 100.100.100.100 으로 가정하였습니다. 실제 IP 에 맞게 변경하여야 한다.

  - 2000 포트로 RMI Registry 와 통신한다.

package example.hello;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {

    public Client() {}

    public static void main(String[] args) {

        String host = (args.length < 1) ? "100.100.100.100" : args[0];

        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        
        try {
            Registry registry = LocateRegistry.getRegistry(host, 2000);
            Hello stub = (Hello) registry.lookup("Hello");
            String response = stub.sayHello();
            System.out.println("response: " + response);
        } catch (Exception e) {
            System.err.println("Client exception: " + e.toString());
            e.printStackTrace();
        }
    }
}


서버 측 server.policy 파일

위치 : /home/user/rmi/bin

grant codeBase "file:/home/user/rmi/bin/*" {
    permission java.security.AllPermission;
};

 

클라이언트 측 client.policy 파일

위치 : D:/eclipse-workspace/RMI/bin

grant codeBase "file:D:/eclipse-workspace/RMI/bin/*" {
    permission java.security.AllPermission;
};

 

[프로그램 띄우기]

1) RMI Registry 구동

  - 클래스를 찾지 못할 경우 -J-Djava.class.path= 옵션으로 클래스 경로를 지정해 준다.

  - RMI Registry 포트를 2000 으로 하였다.

  - 백그라운드로 구동한다.

rmiregistry 
  -J-Djava.class.path=/home/user/rmi/bin 
  2000 
  &

 

2) 서버 측 프로그램 구동

  - 서버 측 프로그램을 구동할 때 java.rmi.server.hostname 환경 값을 설정해 주어야 한다.

   호스트 명과 서버의 아이피가 일치하면 호스트 명을 써주면 되지만, 그렇지 않을 경우 IP를 직접 입력한다.

  - 백그라운드로 구동한다.

java 
  -classpath /home/user/rmi/bin 
  -Djava.security.policy=server.policy 
  -Djava.rmi.server.codebase=file:/home/user/rmi/bin/ 
  -Djava.rmi.server.hostname=100.100.100.100 
  example.hello.Server 
  &

 

3) 서버 측 포트 LISTEN 확인

  - 본 프로그램에서는 서버 측에서 RMI Registry 포트를 2000, Remote Object 포트를 2002 으로 하였다.

   두 TCP 포트를 서버에서 인바운드로 개방해 주어야 한다.

netstat -anp | grep LISTEN | grep 2000
tcp6 0 0 :::2000 :::* LISTEN 27187/rmiregistry

netstat -anp | grep LISTEN | grep 2002
tcp6 0 0 :::2002 :::* LISTEN 27200/java

 

4) 클라이언트 측 프로그램 구동

  - Java Policy client.policy 파일을 연동하여 구동한다.

java 
  -classpath D:\eclipse-workspace\RMI\bin;. 
  -Djava.security.policy=client.policy 
  -Djava.rmi.server.codebase=file:/D:/eclipse-workspace/RMI/bin/ 
  example.hello.Client

 

5) 프로그램 실행 결과

response: Hello, world!

 

 

서버(Linux)에서 프로그램의 클래스 위치는 /home/user/rmi/bin

클라이언트(Windows)에서 프로그램의 클래스 위치는 D:/eclipse-workspace/RMI/bin

으로 하였다.

 


윈도우즈에서는 서버 프로그램을 구동할 때 start rmiregistry ..., start java ... 와 같이 한다.

start rmiregistry -J-Djava.class.path=D:/eclipse-workspace/RMI/bin 2000

start java
    -classpath D:/eclipse-workspace/RMI/bin 
    -Djava.security.policy=server.policy 
    -Djava.rmi.server.codebase=file:D:/eclipse-workspace/RMI/bin/ 
    -Djava.rmi.server.hostname=100.100.100.100
    example.hello.Server

 

 

보안 정책과 관련한 policy 파일을 지정하는 부분을 Java 소스 코드 내에서 해야하는 경우가 있을 수 있다.
그럴 때는 아래와 같이 한다.
 
1) 우선 아래를 적용하고
System.setProperty("java.security.policy","file:/C:/Documents/rmi.policy");
 
2) 그 다음에 아래를 적용한다.
if (System.getSecurityManager() == null) {
    System.setSecurityManager(new SecurityManager());
}

 

 

[참조한 웹 페이지]

  https://docs.oracle.com/javase/tutorial/rmi/overview.html

  https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/hello/hello-world.html

  https://stackoverflow.com/questions/15685686/java-rmi-connectexception-connection-refused-to-host-127-0-1-1

  https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/faq.html#domain

  https://stackoverflow.com/questions/3071376/what-port-is-used-by-java-rmi-connection

  https://docs.oracle.com/javase/7/docs/technotes/tools/windows/rmic.html

  https://stackoverflow.com/questions/9440619/how-do-i-set-the-classpath-that-rmiregistry-uses

  https://www.linuxquestions.org/questions/programming-9/java-rmi-on-linux-connection-problems-875214/

  https://zetawiki.com/wiki/리눅스_포트_사용하는_프로세스_확인

  https://www.linuxquestions.org/questions/programming-9/java-rmi-on-linux-connection-problems-875214/

댓글

이름               비밀번호 
내용
비밀번호를 확인합니다.

댓글 등록시 입력한 비밀번호를 입력해주시기 바랍니다.