Transcript Java_RMI

Java RMI (Remote Method Invocation)
Youn-Hee Han
[email protected]
LINK@KOREATECH
http://link.koreatech.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이 수행
- 즉, skeleton이 기본적으로 만들어지지 않음
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;
}
D:/webservice/rmi/server>javac Hello.java
Java 소스가 D:/>webservice/rmi에 있음을 가정
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에게 문자열 반환
D:/webservice/rmi/server>javac HelloImpl.java
10
원격 객체 및 서버프로그램 작성
HelloServer.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
D:/webservice/rmi/server>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);
}
원격객체의 메소드
호출
}
D:/webservice/rmi/client>javac HelloClient.java
원격지에 생성된 서버 객체에
접근하기 위해서는 localhost
대신에 원격지 컴퓨터의 IP
주소를 입력
12
stub와 skeleton 생성
JDK에서 제공하는 rmic를 실행하여 생성
D:/webservice/rmi/server>rmic
D:\java\test\RMI>rmic
HelloImpl HelloImpl
D:/webservice/rmi/server>dir
….
Hello.java
Hello.class
HelloImpl.java
HelloImpl.class HelloImpl_Stub.class
HelloImpl_Skel.class
8개 파일
7,008 바이트
3 디렉터리 2,813,145,088 바이트 남음
13
RMI Registry 실행
Remote object의 registry 관리
 서버의 원격객체 등록 받고, 클라이언트의 요청에 의하여 서버를
검색해서 클라이언트에게 반환해주는 역할
기본적인 RMI Registry 실행

디폴트 port : 1099
Note: HelloImpl 클래스 파일이 있는 디렉토리에서 실행
D:/webservice/rmi/server>rmiregistry
RMI Registry가 실행될 특정 포트번호 지정
 서버와 클라이언트에서도 같은 포트번호를 명시적으로 지정
D:/webservice/rmi/server>rmiregistry 5000
 포트 번호 명기 필요성
 HelloImpl.java

Naming.rebind("//localhost/hello:5000", h);
 HelloClient.java

Hello h = (Hello) Naming.lookup("//localhost/hello:5000");
14
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:/webservice/rmi/server>java HelloImpl
Hello Server ready
새로운 cmd 창에서 수행
클라리언트 프로그램 실행

클라이언트 컴퓨터 상에 원격객체의 인터페이스와 Stub 클래스가
존재해야함
D:/webservice/rmi/client>java HelloClient
HelloClient : Hello World
새로운 cmd 창에서 수행
D:/webservice/rmi/client>
16
RMI 구현 정리
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
HelloImpl_Stub.class
HelloClient.class
Client
HelloImpl_Stub.class
HelloServer.class
전달
HelloImpl.class
Server
17
RMI Calculator Example - 1
Numbers.java
import java.util.HashMap;
import java.io.Serializable;
public class Numbers implements Serializable {
HashMap numbers;
public Numbers(int size) {
numbers = new HashMap(size);
}
public void setNumber(int key, int value) {
numbers.put(key, value);
}
public int getNumber(int key) {
return (Integer)numbers.get(key);
}
}
public int size() {
return numbers.size();
}
18
RMI Calculator Example - 1
Calc.java
import java.rmi.*;
public interface Calc extends Remote {
public int sum(int a,int b) throws RemoteException;
public int sumNumbers(Numbers c) 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;
}
public int sumNumbers(Numbers c) throws RemoteException {
int sum = 0;
for (int i = 0 ; i < c.size() ; i++) {
sum = sum + c.getNumber(i);
}
return sum;
}
}
19
RMI Calculator Example - 2
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.....");
}
}
D:/webservice/rmi/server>javac Numbers.java
D:/webservice/rmi/server>javac Calc.java
D:/webservice/rmi/server>javac CalcImpl.java
D:/webservice/rmi/server>javac CalcServer.java
D:/webservice/rmi/server>rmic CalcImpl
rmic를 실행하여 stub 생성
20
RMI Calculator Example - 3
CalcClient.java
import java.rmi.*;
import java.rmi.server.*;
import java.util.Random;
public class CalcClient {
public static void main(String[] args) throws Exception {
int size = 10;
Numbers nums = new Numbers(size);
Random random = new Random(System.currentTimeMillis());
for (int i = 0 ; i < size ; i++) {
nums.setNumber(i, random.nextInt(1000));
}
String url = "//localhost/calc";
Calc remoteCalcObject = (Calc)Naming.lookup(url);
System.out.println("Got remote object: " + remoteCalcObject);
System.out.println(" 1 + 2 = " + remoteCalcObject.sum(1,2) );
System.out.println(" Sum of " + size + " Random Numbers is " +
remoteCalcObject.sumNumbers(nums) );
}
}
server 폴더에서 다음 파일들을 client 폴더로 복사
: Calc.class, Numbers.class, CalcImpl_Stub.class
D:/webservice/rmi/client>javac CalcClient.java
21
RMI Calculator Example - 4
RMI Registry 실행
D:/webservice/rmi/server>rmiregistry
서버프로그램 실행
D:/webservice/rmi/server>java CalcServer
새로운 cmd 창에서 수행
클라이언트 프로그램 실행
D:/webservice/rmi/client>java CalcClient
새로운 cmd 창에서 수행
22