Transcript Java_RMI

Java RMI (Remote Method Invocation)
Youn-Hee Han
[email protected]
Korea University of Technology and Education
Internet 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
Client
Server.hello()
RMI Interface
Internet
Server
hello()
2
RMI의 특징
RMI의 특징

복잡한 객체들의 전달과 반환이 가능
 저수준 (Low Level)의 프로토콜 설계가 요구되지 않음

원격 메소드의 호출과 리턴값 반환에 대한 트랜잭션 확립 제공
 클라이언트에서 복잡한 트랜잭션을 취급할 필요가 없게 됨

처리 능력이 강력한 서버에 계산 작업을 분산 할당
 빈약한 하드웨어 자원의 클라이언트에 부담을 주지 않음
단점


사이즈가 크거나 복잡한 객체들이 전달될 때 오버헤드가 큼
네트워크 처리 시간이 다소 느림
3
RMI의 특징
Object Serialization


RMI는 내부적으로 객체 스트림을 네트워크 상에서 읽고 쓰기 위한
객체직렬화 (Object Serialization) 기능을 사용
자바는 매우 편리하게 객체를 직렬화할 수 있는 기능을 지님
Marshaling/Unmarsharling
객체 직렬화의 전문적 용어
 Marsharling

 파라미터나 반환값들이 네트워크를 통해 전송 될 수 있는 바이트
스트림으로 변환되는 프로세스
 Unmarsharling
 바이트 스트림을 실제 파라미터 값이나 반환값으로 변환하는 것
4
RMI의 구조
RMI 계층 모델
논리적 호출
서버 프로그램
Skeleton
(서버의 소프트웨어)
원격 참조 계층
클라이언트 프로그램
lookup()
Stub
RMI Interface
전송 계층
TCP/IP
원격 참조 계층
전송 계층
물리적 호출
TCP/IP
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
5
RMI의 구조
Stub 과 Skeleton의 역할 및 RMI 구조
parameters
Marshalled
parameters
Stub
Object
Return
value

Method
invocation
on client
Skeleton
Object
Marshalled
return value
Server
Object
Method
invocation
on server
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

6
RMI 개발순서
RMI 개발순서
1.
2.
3.
4.
서비스할 원격객체의 Remote Interface 작성
원격 객체 및 server program 작성
원격 객체를 사용 할 client program을 작성
stub와 skeleton 생성
최근 자바 버전에서는 skeleton의 역할까지 stub이 수행
5. RMI Registry 실행
6. Server Program 실행
7. Client Program 실행
(1)
(2)
Define Remote Interface
Implement the Interface
javac
Run the stub
compile
(3)
uses
Stub
Implement Client
javac
Class
Start Client (7)
Class
rmic
(4)
Skeleton
(5) Start RMI Registry
(6) Start server object
Register remote Objects
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
서비스할 원격객체의 interface 작성
원격객체가 실제 제공할 모든 메소드의 형태 정의
작성시 반드시 지켜야 할 규칙



java.rmi.Remote 인터페이스 상속받아야 함
반드시 모든 메소드의 접근 지정자는 public
모든 메소드는 java.rmi.RemoteException을 발생
Hello.java
import java.rmi.*;
public interface Hello extends Remote {
public String sayHello() throws java.rmi.RemoteException;
}
C:\>javac Hello.java
9
원격 객체 및 서버프로그램 작성
원격 인터페이스에서 정의된 메소드들을 실제 구현
작성시 반드시 지켜야할 규칙



원격인터페이스의 모든 메소드 구현
java.rmi.server.UnicastRemoteObject 클래스를 상속 받아야 함
java.rmi.Naming.rebind()메소드를 사용해서 원격객체를 RMI
Registry에 등록
HelloImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class HelloImpl extends UnicastRemoteObject implements Hello {
생성자는 기본적으로
부모클래스의 생성자
호출
public HelloImpl() throws RemoteException {
super();
}
}
public String sayHello() throws RemoteException {
return "Hello World";
}
원격 객체를 호출한
Client에게 문자열 반환
C:\>javac HelloImpl.java
10
원격 객체 및 서버프로그램 작성
HelloImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class HelloServer {
public static void main(String[] args) throws Exception {
HelloImpl h = new HelloImpl();
Naming.bind("//localhost/hello", h);
System.out.println("Hello Server ready");
}
}
새로운
HelloImpl객체를
생성하고 “hello”라는
이름으로 bind
C:\>javac HelloServer.java
11
Client Program을 작성
서버의 RMI Registry로 부터 Remote Reference 얻어오기
java.rmi.Naming클래스의 lookup()메소드 사용 (형변환 必)

Remote Reference 를 통해 원하는 메소드 호출
HelloClient.java
import java.rmi.*;
public class HelloClient {
public static void main(String[] args) throws Exception {
서버의 RMI
Reistry로부터
원겨참조자 얻어오기
Hello h = (Hello) Naming.lookup("//localhost/hello");
String message = h.sayHello();
System.out.println("HelloClient: " +message);
}
원격객체의 메소드
호출
}
C:\>javac HelloClient.java
12
stub와 skeleton 생성
JDK에서 제공하는 rmic를 실행하여 생성
D:\java\test\RMI>rmic
D:\java\test\RMI>rmicHelloImpl
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
HelloImpl_Stub.class HelloImpl_Skel.class
8개 파일
7,008 바이트
3 디렉터리 2,813,145,088 바이트 남음
D:\java\test\RMI>
D:\java\test\RMI>rmic
D:\java\test\RMI>rmicHelloImpl
HelloImpl
D:\java\test\RMI>dir /w
….
Hello.java
Hello.class
HelloImpl.java
HelloClient.java
HelloImpl.class
HelloClient.class
Java2 이후
HelloImpl_Stub.class
7개 파일
7,008 바이트
3 디렉터리 2,813,145,088 바이트 남음
D:\java\test\RMI>
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
D:\java\test\RMI>rmiregistry
RMI Registry가 실행될 특정 포트번호 지정

서버와 클라이언트에서도 같은 포트번호를 명시적으로 지정
D:\java\test\RMI>rmiregistry 5000

포트 번호 명기 필요성
 HelloImpl.java

Naming.rebind("//localhost/hello:5000", h);
 HelloClient.java

Hello h = (Hello) Naming.lookup("//localhost/hello: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 배열을
반환
서버/클라이언트 프로그램 실행
서버프로그램 실행
D:\java\test\RMI>java HelloImpl
Hello Server ready
클라리언트 프로그램 실행

클라이언트 컴퓨터 상에 원격객체의 인터페이스와 Stub 클래스가
존재해야함
D:\java\test\RMI>java HelloClient
Hello Client : Hello World
D:\java\test\RMI>
17
정리
Hello.java
implement
HelloImpl.java
javac HelloImpl.java
HelloImpl.class
rmic HelloImpl
HelloClient.java
javac HelloClient.java
generates
HelloServer.java
javac HelloServer.java
Hello.class
Hello.class
ProductImpl_Stub.class
HelloClient.class
Client
HelloImpl_Skel.class
HelloServer.class
HelloImpl.class
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