200 likes | 605 Views
Java RMI (Remote Method Invocation). Youn-Hee Han yhhan@kut.ac.kr Korea University of Technology and Education Internet Computing Laboratory http://icl.kut.ac.kr. RMI 의 정의. Java RMI (Remote Method Invocation) 지역적으로 멀리 떨어진 다른 가상 머신 (Virtual Machine) 에 있는 객체의 Method 를 호출하여 실행하는 기술
E N D
JavaRMI (Remote Method Invocation) Youn-Hee Han yhhan@kut.ac.kr Korea University of Technology and EducationInternet Computing Laboratory http://icl.kut.ac.kr
RMI의 정의 • Java RMI (Remote Method Invocation) • 지역적으로 멀리 떨어진 다른 가상 머신 (Virtual Machine)에 있는 객체의 Method를 호출하여 실행하는 기술 • 기본원리 : 1980년대 사용하던 RPC (Remote Procedure Call)방식 • 클라이언트 객체는 Remote Method를 자신이지닌 Local Method를 호출하는 것처럼 간단히 수행 RMI Interface RMI Interface Client Server.hello() Server hello() Internet
RMI의 특징 • RMI의 특징 • 복잡한 객체들의 전달과 반환이 가능 • 저수준 (Low Level)의 프로토콜 설계가 요구되지 않음 • 원격 메소드의 호출과 리턴값 반환에 대한 트랜잭션 확립 제공 • 클라이언트에서 복잡한 트랜잭션을 취급할 필요가 없게 됨 • 처리 능력이 강력한 서버에 계산 작업을 분산 할당 • 빈약한 하드웨어 자원의 클라이언트에 부담을 주지 않음 • 단점 • 사이즈가 크거나 복잡한 객체들이 전달될 때 오버헤드가 큼 • 네트워크 처리 시간이 다소 느림
RMI의 특징 • ObjectSerialization • RMI는 내부적으로 객체 스트림을 네트워크 상에서 읽고 쓰기 위한 객체직렬화 (Object Serialization) 기능을 사용 • 자바는 매우 편리하게 객체를 직렬화할 수 있는 기능을 지님 • Marshaling/Unmarsharling • 객체직렬화의 전문적 용어 • Marsharling • 파라미터나 반환값들이 네트워크를 통해 전송 될 수 있는 바이트 스트림으로 변환되는 프로세스 • Unmarsharling • 바이트 스트림을 실제 파라미터 값이나 반환값으로 변환하는 것
RMI의 구조 • RMI 계층 모델 • RMI Interface 및 Stub/Skeleton계층 • 자바에서제공하는 rmic 컴파일러를 사용하여 클라이언트와 서버는 양자간의 원격 참조 객체 및 Stub/Skeleton을 생성 • Stub • marshals parameter data (serialization) • unmarshals results data (deserialization) • Skeleton (not required with recent Java) • unmarshals parameter data • marshals results data 논리적 호출 서버 프로그램 클라이언트 프로그램 lookup() Skeleton (서버의 소프트웨어) Stub 원격 참조 계층 원격 참조 계층 RMI Interface 전송 계층 전송 계층 TCP/IP TCP/IP 물리적 호출
Stub Object Server Object RMI의 구조 • Stub 과 Skeleton의 역할 및 RMI 구조 • Stub 에서서버로 전달되는 information block • 원격 객체의 identifier • 호출 method 번호 • Parameters • Primitive Type(Integer, Byte, …)는 copy by value로 전달 • Reference Type(String Object, Array Object, …)는 Object Copy로 전달 • Skeleton의 중요 역할 • Stub에서 전달된 information block을 해석 • remote method가 실행되는 실제 object에 전달 • remote method의 호출 결과를 marshall하여 client stub로 return Marshalled parameters parameters Skeleton Object Marshalled return value Method invocation on client Method invocation on server Return value
Define Remote Interface Implement the Interface javac Class Run the stub compile rmic uses Implement Client Stub Skeleton javac Start RMI Registry Class Start server object Start Client Register remote Objects RMI 개발순서 • RMI 개발순서 1. 서비스할 원격객체의 Remote Interface 작성 2. 원격 객체 및 server program 작성 3. 원격 객체를 사용 할 client program을 작성 4. stub와 skeleton 생성 최근 자바 버전에서는 skeleton의 역할까지 stub이 수행 5. RMI Registry 실행 6. Server Program 실행 7. Client Program 실행 (1) (2) (3) (4) (5) (6) (7) 7
RMI 관련 패키지 • Core packages for RMI: • java.rmi • java.rmi.server • Main interface for RMI: • java.rmi.Remote • Core classes for RMI: • java.rmi.server.UnicastRemoteObject • java.rmi.RemoteException • java.rmi.Naming 8
원격객체가 실제 제공할 모든 메소드의 형태 정의 작성시 반드시 지켜야 할 규칙 java.rmi.Remote 인터페이스 상속받아야 함 반드시 모든 메소드의 접근 지정자는 public 모든 메소드는 java.rmi.RemoteException을 발생 import java.rmi.*; publicinterface Helloextends Remote{ publicString sayHello()throws java.rmi.RemoteException; } Hello.java 서비스할 원격객체의 interface 작성 C:\>javac Hello.java
원격 인터페이스에서 정의된 메소드들을 실제 구현 작성시 반드시 지켜야할 규칙 원격인터페이스의 모든 메소드 구현 java.rmi.server.UnicastRemoteObject 클래스를 상속 받아야 함 java.rmi.Naming.rebind()메소드를 사용해서 원격객체를 RMI Registry에 등록 import java.rmi.*; import java.rmi.server.*; public class HelloImplextends UnicastRemoteObject implements Hello { } 원격 객체 및 서버프로그램 작성 HelloImpl.java 생성자는 기본적으로 부모클래스의 생성자 호출 public HelloImpl() throws RemoteException { super(); } 원격 객체를 호출한 Client에게 문자열 반환 public String sayHello() throws RemoteException { return "Hello World"; } C:\>javac HelloImpl.java 10
import java.rmi.*; import java.rmi.server.*; public class HelloServer{ public static void main(String[] args) throws Exception { } } 원격 객체 및 서버프로그램 작성 HelloImpl.java 새로운 HelloImpl객체를 생성하고 “hello”라는 이름으로 bind HelloImpl h = new HelloImpl(); Naming.bind("//localhost/hello", h); System.out.println("Hello Server ready"); C:\>javac HelloServer.java 11
import java.rmi.*; public class HelloClient { public static void main(String[] args) throws Exception { System.out.println("HelloClient: " +message); } } Client Program을 작성 • 서버의 RMI Registry로 부터 Remote Reference 얻어오기 • java.rmi.Naming클래스의 lookup()메소드 사용 (형변환 必) • Remote Reference 를 통해 원하는 메소드 호출 HelloClient.java 서버의 RMI Reistry로부터 원겨참조자 얻어오기 Hello h = (Hello) Naming.lookup("//localhost/hello"); String message = h.sayHello(); 원격객체의 메소드 호출 C:\>javac HelloClient.java 12
D:\java\test\RMI>rmic HelloImpl D:\java\test\RMI>dir /w …. Hello.java Hello.class HelloImpl.java HelloClient.java HelloImpl.class HelloClient.class HelloImpl_Stub.class HelloImpl_Skel.class 8개 파일 7,008 바이트 3 디렉터리 2,813,145,088 바이트 남음 D:\java\test\RMI> D:\java\test\RMI>rmic HelloImpl HelloImpl_Stub.class HelloImpl_Skel.class stub와 skeleton 생성 • JDK에서 제공하는 rmic를 실행하여 생성 D:\java\test\RMI>rmic HelloImpl D:\java\test\RMI>dir /w …. Hello.java Hello.class HelloImpl.java HelloClient.java HelloImpl.class HelloClient.class 7개 파일 7,008 바이트 3 디렉터리 2,813,145,088 바이트 남음 D:\java\test\RMI> D:\java\test\RMI>rmic HelloImpl HelloImpl_Stub.class Java2 이후 13
stub와 skeleton 생성 • Java 1.2 이후 skeleton 생성이 안됨 • Skeleton code does not need be specific for each type of server object • Generic skeleton code can use Java reflection to make the appropriate server-side dispatch of a request • Allows java programs to inspect Classes to determine information about a Class at runtime: • The methods it defines • The members it has • A Class exists to model a method • Methods can be “invoked” generically at runtime • Starting with Java 2 (1.2) skeletons were made optional • Pass a command line option to rmic (-v1.2) 14
RMI Registry 실행 • Remote object의 registry 관리 • 서버의 원격객체 등록 받고, 클라이언트의 요청에 의하여 서버를 검색해서 클라이언트에게 반환해주는 역할 • 기본적인 RMI Registry 실행 • 디폴트 port : 1099 • RMI Registry가 실행될 특정 포트번호 지정 • 서버와 클라이언트에서도 같은 포트번호를 명시적으로 지정 • 포트 번호 명기 필요성 • HelloImpl.java • Naming.rebind("//localhost/hello:5000", h); • HelloClient.java • Hello h = (Hello) Naming.lookup("//localhost/hello:5000"); D:\java\test\RMI>rmiregistry D:\java\test\RMI>rmiregistry 5000 Note: HelloImpl 클래스 파일이 있는 디렉토리에서 실행 15
RMI Registry 실행 • java.rmi.Naming • static Remote lookup(String url) • 해당 url에 대한 remote object를 return • static void bind(String name, Remote obj) • 해당 name을 obj remote object에 binding • static void unbind(String name) • name의 binding 해제 • static void rebind(String name, Remote obj) • bind와 같으나 기존 binding이 존재할 경우 대체함 • static String[] list(String url) • 해당 url에 위치한 registry에 등록된 object url들의 string 배열을 반환
서버/클라이언트 프로그램 실행 • 서버프로그램 실행 • 클라리언트 프로그램 실행 • 클라이언트 컴퓨터 상에 원격객체의 인터페이스와 Stub 클래스가 존재해야함 D:\java\test\RMI>java HelloImpl Hello Server ready D:\java\test\RMI>java HelloClient Hello Client : Hello World D:\java\test\RMI> 17
정리 Hello.java implement HelloImpl.java javacHelloImpl.java HelloImpl.class rmic HelloImpl HelloClient.java HelloServer.java generates javacHelloClient.java javacHelloServer.java Hello.class Hello.class ProductImpl_Stub.class HelloImpl_Skel.class HelloServer.class HelloClient.class HelloImpl.class Client Server 18
Other Example Calc.java import java.rmi.*; public interface Calc extends Remote { public int sum(int a,int b) throws RemoteException; } CalcImpl.java import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*; public class CalcImpl extends UnicastRemoteObject implements Calc { CalcImpl() throws RemoteException { super(); } public int sum(int a,int b) throws RemoteException { return a + b; } } 19
Other Example CalcServer.java import java.rmi.*; import java.rmi.server.*; public class CalcServer { public static void main(String args[]) throws Exception { CalcImpl calc = new CalcImpl(); Naming.rebind("//localhost/calc" , calc); System.out.println("Server waiting....."); } } CalcClient.java import java.rmi.*; import java.rmi.server.*; public class CalcClient { public static void main(String[] args) throws Exception { System.out.println("Security Manager loaded"); String url = "//localhost/calc"; Calc remoteObject = (Calc)Naming.lookup(url); System.out.println("Got remote object"); System.out.println(" 1 + 2 = " + remoteObject.sum(1,2) ); } } 20