제목 | Java RMI | ||||||
글쓴이 | 이지섭 | 작성일 | 2018-01-18 | 수정일 | 2024-08-09 | 조회수 | 6981 |
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(); } } }
위치 : /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
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 -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://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/ | |||||||
로그인 | Language : |