18. rmi 를 이용한 원격 배포

22
18. RMI 를 를를를 를를 를를

Upload: waseem

Post on 22-Feb-2016

80 views

Category:

Documents


0 download

DESCRIPTION

18. RMI 를 이용한 원격 배포. 원격 메소드 호출 방법 (1/2). 클라이언트와 서버 애플리케이션을 만든다 . 서버 애플리케이션은 클라이언트에서 호출하고자 하는 메소드를 가지고 있는 객체가 들어있는 원격 서비스이다 . 클라이언트 힙. 서버 힙. 클라이언트 객체. 서비스 객체. 원격 메소드 호출 방법 (2/2). - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 18. RMI 를 이용한 원격 배포

18. RMI 를 이용한 원격 배포

Page 2: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 메소드 호출 방법 (1/2)

2

클라이언트와 서버 애플리케이션을 만든다 . 서버 애플리케이션은 클라이언트에서 호출하고자 하는 메소드를 가지고 있는 객체가 들어있는 원격 서비스이다 .

클라이언트 힙 서버 힙

Page 3: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 메소드 호출 방법 (2/2)

3

클라이언트와 서버 보조 객체 (helper) 를 만든다 . 이 보조 객체는 클라이언트와 서비스가 마치 같은 힙 안에 들어있는 것처럼 행동할 수 있도록 저 수준 네트워킹 , 입출력과 관련된 자질구레한 일을 모두 처리해주는 역할을 한다 .

클라이언트 힙 서버 힙

Page 4: 18. RMI 를 이용한 원격 배포

Head First JAVA

보조 객체의 역할

4

클라이언트 힙 서버 힙

클라이언트 객체는 진짜 서비스에 대해 메소드를 호출한다고 생각한다 . 클라이언트 보조 객체가 실제로 자신이 원하는 작업을 처리해주는 객체라고 생각하는 것이다 .

클라이언트 보조 객체는 서비스인 것처럼 행동하지만 사실은 매개해주는 역할을 할 뿐이다 .

서비스 보조 객체는 클라이언트 보조 객체로부터 요청을 받아서 포장을 풀고 진짜 서비스에 있는 메소드를 호출한다 .

서비스 객체가 진짜 서비스이다 . 클라이언트가 원했던 일을 처리하는 진짜 메소드는 바로 여기에 들어있다 .

Page 5: 18. RMI 를 이용한 원격 배포

Head First JAVA

메소드 호출 과정 (1/3)

5

클라이언트 힙 서버 힙

클라이언트 객체에서 클라이언트 보조 객체에 있는 doBigThing()을 호출한다 .

doBigThing()

Page 6: 18. RMI 를 이용한 원격 배포

Head First JAVA

메소드 호출 과정 (2/3)

6

클라이언트 힙 서버 힙

클라이언트 보조 객체에서 메소드 호출에 대한 정보 ( 인자 , 메소드명 등 ) 를 포장해서 네트워크를 통해 서비스 보조 객체로 보낸다 .

클라이언트에서 메소드를 호출하고 싶어한다 .

Page 7: 18. RMI 를 이용한 원격 배포

Head First JAVA

메소드 호출 과정 (3/3)

7

클라이언트 힙 서버 힙

서비스 보조 객체에서 클라이언트 보조 객체로부터 받은 정보를 풀어서 어떤 객체의 어떤 메소드를 호출할지 알아낸 다음 진짜 서비스 객체에 있는 진짜 메소드를 호출한다 .

doBigThing()

Page 8: 18. RMI 를 이용한 원격 배포

Head First JAVA

RMI 보조 객체

8

클라이언트 힙 서버 힙

RMI 스터브

자바 RMI 가 보조 객체를 제공하는데 클라이언트 보조 객체는 ‘ 스터브 (stub)’ 고 서버 보조 객체는 ‘스켈레톤 (skeleton)’

이다 .

RMI 스켈레톤

Page 9: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 서비스를 만드는 방법

9

원격 인터페이스를 만든다 .

원격 인터페이스를 구현한 클래스를 만든다 .

rmic 를 이용하여 스터브와 스켈레톤을 생성한다 .

RMI 레지스트리 (rmiregistry) 를 시작한다 .

원격 서비스를 시작한다 .

Page 10: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 생성 (1/3)

10

java.rmi.Remote 를 확장한다 .Remote 는 표지 인터페이스 ( 아무 메소드도 없는 인터페이스 ) 이다 . 하지만 RMI 에서 특별한 의미를 가지기 때문에 이 규칙을 지켜야 한다 . 여기에서 extends 를 써야 하는데 이렇게 한 인터페이스 다른 인터페이스를 구현할 수는 없지만 확장하는 것은 가능하다 .

public interface MyRemote extends Remote {

인터페이스가 원격 메소드 호출을 위한 것이라고 선언해야 한다 .

public interface MyRemote extends Remote {}

MyRemote.java

Page 11: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 생성 (2/3)

11

모든 메소드에서 RemoteException 을 던진다는 것을 선언한다 .원격 인터페이스는 클라이언트에서 서비스를 위한 다형적인 유형으로 사용하기 위한 것이다 . 클라이언트에서 그 원격 인터페이스를 구현하는 객체( 스터브 객체 ) 에 대한 메소드를 호출하는데 스터브 객체에서는 네트워킹과 입출력을 처리하기 때문에 안 좋은 일이 일어날 수 있기 때문에 클라이언트에서는 원격 예외를 처리하거나 선언해야 한다 .import java.rmi.*; // Remote 인터페이스는 java.rmi 에 들어있다 .

public interface MyRemote extends Remote {public String sayHello() throws

RemoteException;}

원격 메소드 호출은 모두 위험한 것으로 간주됨

Page 12: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 생성 (3/3)

12

인자나 리턴값이 원시유형 또는 Serializable 유형인지 확인한다 .원격 메소드에 대한 인자 ( 리턴값도 마찬가지 ) 는 포장해서 네트워크를 통해 전달해야 하는데 그 과정에서 직렬화가 필요하다 . 원시유형 , String 을 비롯한 API 에 들어있는 대부분의 유형은 별 문제없이 쓸수 있지만 직접 만든 유형을 사용할 때는 그 클래스를 만들 때 Serializable 인터페이스를 구현했는지 꼭 확인해봐야 한다 .

public String sayHello() throws RemoteException;

Page 13: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 구현 클래스 생성 (1/4)

13

원격 인터페이스를 구현한다 .서비스에서는 클라이언트에서 호출할 메소드가 있는 원격 인터페이스를 구현해야 한다 .

public class MyRemoteImpl extends UnicastRemoteOnject implements MyRemote {

public String sayHello() {return “Server says, ‘Hey’”;

}// 또 다른 코드

}

컴파일러에서 아까 구현한 인터페이스에 들어있는 모든 메소드를 구현했는지 확인해줌

public interface MyRemote extends Remote {}

MyRemoteImpl.java

Page 14: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 구현 클래스 생성 (2/4)

14

UnicastRemoteObject 를 확장한다 .원격 서비스 객체 역할을 하려면 ‘원격으로 돌아가는 것과 관련된 기능’이 들어있어야 하는데 UnicastRemoteObject(java.rmi.server 패키지에 들어있음 ) 를 확장하고 그 클래스에서 필요한 작업을 처리하게 하는 것이 가장 간단한 방법이다 .

public class MyRemoteImpl extends UnicastRemoteOnject implements MyRemote {

Page 15: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 구현 클래스 생성 (3/4)

15

RemoteException 을 선언하는 아무 인자도 없는 생성자를 만든다 .이 클래스의 상위클래스인 UnicastRemote 의 한 가지 문제점은 RemoteException 을 던진다는 것인데 이런 문제를 해결할 수 있는 유일한 방법은 원격 인터페이스를 구현한 클래스의 생성자도 RemoteException을 던지는 것으로 선언하는 것이다 . 상위클래스 생성자에서 예외를 던지면 별 수 없이 그 클래스의 생성자에서도 예외를 던지는 것으로 선언해야 한다 .

public MyRemoteImpl() throws RemoteException { }

이 클래스의 생성자에서도 예외를 던질 수 있음을 선언하기 위한 코드이므로 아무 내용을 집어넣지 않아도 된다 .

Page 16: 18. RMI 를 이용한 원격 배포

Head First JAVA

원격 인터페이스 구현 클래스 생성 (4/4)

16

서비스를 RMI 레지스트리에 등록한다 .이제 원격 서비스가 만들어졌으므로 원격 클라이언트에서 그 서비스를 사용할 수 있게 클래스의 인스턴스를 만들고 RMI 레지스트리에 집어넣는다 . 원격 인터페이스를 구현한 클래스를 등록하면 클라이언트에서 써야하므로 RMI 시스템에서는 서비스를 스터브로 대체하고 그 스터브를 레지스트리에 집어넣는다 . 서비스를 등록할 때는 java.rmi.Naming 클래스에 있는 정적 메소드인 rebind() 메소드를 이용하면 된다 .

try {MyRemote service = new

MyRemoteImpl();Naming.rebind(“Remote Hello”,

service);} catch (Exception ex) { … }

서비스에 클라이언트의 레지스트리에서 이 서비스를 찾을 때 사용하는 이름을 붙여주고 RMI 레지스트리에 등록한다 .

Page 17: 18. RMI 를 이용한 원격 배포

Head First JAVA

스터브와 스켈레톤 생성

17

원격 인터페이스를 구현한 클래스에 대해 rmic 를 실행한다 .자바 SDK 에 들어있는 rmic 도구는 서비스 인터페이스를 구현한 클래스를 받아서 스터브와 스켈레톤을 생성해준다 . 이름을 정할 때는 dnjsrur 인터페이스를 구현한 클래스명 뒤에 _Stub 와 _Skel 을 각각 추가한다 . 이렇게 만들어진 클래스는 현재 디렉토리에 저장되고 rmic 에서 인터페이스를 구현한 클래스를 볼 수 있어야 하므로 그 클래스가 들어있는 디렉토리에서 rmic 를 실행할 가능성이 높다 .

101101 10 110 10 11 0001 1000 01

MyServiceImpl_Stub.class

101101 10 110 10 11 0001 1000 01

MyRemoteImpl_Skel.class

Page 18: 18. RMI 를 이용한 원격 배포

Head First JAVA

rmiregisty 실행 및 서비스 시작

18

터미널을 열고 rmiregistry 를 시작한다 .반드시 클래스에 접근할 수 있는 디렉토리에서 실행시켜야 하는데 가장 간단한 방법은 classex 디렉토리에서 실행시키는 것이다 .

다른 터미널을 열고 서비스를 시작한다 .원격 인터페이스를 구현한 클래스의 main() 메소드에서 시작할 수도 있고 다른 구동용 클래스에서 시작할 수도 있을 것이다 .

Page 19: 18. RMI 를 이용한 원격 배포

Head First JAVA

서버용 코드 (1/2)

19

import java.rmi*;

public interface MyRemote extends Remote {

public String sayHello() throws

RemoteException;

}

원격 인터페이스

RemoteException 과 Remote 인터페이스가 java.rmi 패키지에 들어 있다 .

인터페이스가 반드시 java.rmi.Remote 를 확장해야 한다 .

모든 원격 메소드에서 RemoteException 을 선언해야만 한다 .

Page 20: 18. RMI 를 이용한 원격 배포

Head First JAVA

서버용 코드 (2/2)

20

import java.rmi*;import java.rmi.server.*;public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {

public String sayHello() {return “Server says, ‘Hey’”;

} // 모든 인터페이스 메소드를 구현public MyRemoteImpl() throws RemoteException { }public static void main (String[] args) {

try {Myremote service = new MyRemoteImpl();Naming.rebind(“Remote Hello”, service);

} catch (Exception ex) {ex.printStackTrace();

}}

}

원격 서비스 ( 인터페이스를 구현한 클래스 )

UnicastRemoteObjet 가 java.rmi.server 패키지에 들어있음 .

원격 인터페이스를 구현해야 한다 .

상위클래스 생성자에서 예외를 선언하기 때문에 반드시 생성자를 만들어야 함 .

원격 객체를 만들고 Naming.rebind() 정적메소드를 써서 RMI 레지스트리에 결합시킨다 .

Page 21: 18. RMI 를 이용한 원격 배포

Head First JAVA

스터브를 받는 방법

21

클라이언트 힙 서버 힙

클라이언트에서 메소드를 호출할 때 스터브 객체에 대해 메소드를 호출하기 때문에 반드시 스터브 객체를 받아야 한다 .

Remote Hello

RMI 레지스트리( 서버에 있음 )

1

2

3

1. 클라이언트에서 RMI 레지스트리에 대한 룩업 작업을 한다 .

2. RMI 레지스트리에서 스터브 객체를 리턴한다 .

3. 클라이언트에서 실제 서비스에 있는 메소드를 호출하는 것과 같은 방법으로 스터브에 있는 메소드를 호출한다 .

Page 22: 18. RMI 를 이용한 원격 배포

Head First JAVA

클라이언트 코드

22

import java.rmi*;public class MyRemoteClient {

public static void main(String [] args) {new MyRemoteClient().go();

}public void go() {

try {MyRemote service = (MyRemote)

Naming.lookup(“rmi://127.0.0.1/Remote Hello”);

String s = service.sayHello();System.out.println(s);

} catch (Exception ex) {ex.printStackTrace();

}}

}

Naming 클래스가 들어있음

클라이언트에서는 항상 원격 인터페이스를 서비스 유형으로 사용

Lookup() 메소드는 Object 유형을 리턴하기 때문에 인터페이스 유형으로 캐스트해야 함

lookup() 은 Naming 클래스의 정적메소드호스트명 또는 IP 주소와 서비스를 등록할 때 지정한 이름을 쓴다 .