( 분산통신실습 ) RMI RMI 익히기 1. 분산환경에서동작하는 message-passing을이용한 boundedbuffer 해법프로그램을실행해보세요. 소스코드 : ftp://211.119.245.153 -> os -> OSJavaSources -> ch15 -> rmi http://marvel el.incheon.ac.kr의 Information Unix RMI 참조 2. 또, 이예제가웹상에서수행될수있도록수정해보세요. 즉클라이언트프로그램에서이예제의 Producer와 Consumer의동작을모니터링하는 Java applet을작성해보는것입니다. AppletViewer 또는넷스케이프커뮤니케이터로실행 3. BONUS: Java synchronization을이용한 bounded-buffer 해법 ( 운영체제교재 Applied Operating System Concepts 7장 p209 참조 ) 이분산환경에서도동작할수있도록 RMI를이용하여수정해보세요. 실습방법 cseblade.incheon.ac.kr(211.119.245.68) 의 /mysung/2003osreport 디렉토리에자기학번디렉토리를만들고소스프로그램과실행파일을옮겨놓으세요. 1.1
RMI (Remote Method Invocation) RPC 의 Java 버전 저수준 (low-level) 소켓을이용하지않고원격객체의메소드를호출할수있는방법을제공하는객체지향언어인 Java 기반의분산컴퓨팅환경 ( 클라이언트 / 서버지원 ) 을위한미들웨어 (RPC와유사 ) 스레드 (thread) 가원격객체 (Remote Object) 의메소드 (method) 호출 다른 Java Virtual Machine 상에있는객체는 원격 객체 RPC 보다좋은점 객체지향적이다. 프로그램작성및사용이쉽다. 안전하고보안성이있다. 기존시스템과통합해서사용할수있다. 작성절차 원격인터페이스를정의한다. 원격인터페이스를구현 (implement) 하는원격객체 ( 서버 ) 를작성한다. 원격객체를이용하는프로그램 ( 클라이언트 ) 을작성한다. stub 와 skeleton 클래스를생성한다. rmiregistry 를실행시킨다. 서버와클라이언트를실행시킨다. 1.2
RMI (Remote Method Invocation) 1.3
RMI (Remote Method Invocation) RPC versus RMI RPC : Procedural Programming Style RMI : Object-Oriented Programming Style RPC 의매개변수 : Ordinary Data Structures RMI 의매개변수 : Objects Stubs and Skeletons Stub 클라이언트에상주하는원격객체의대리인 (proxy) 매개변수들을 Marshalls ( 메소드이름과인자들의꾸러미생성 ) 해서서버로보냄 Skeleton 서버에상주 매개변수를 Unmarshalls 해서서버에전달함 매개변수 Marshall 된매개변수가 Local (Non-Remote) Objects 이면객체를바이트스트림으로기록해주는객체순서화 (Object Serialization) 기법을이용해서복사에의해 (by Value) 전달 Marshall 된매개변수가 Remote Objects 이면참조에의해 (by Reference) 전달 : RMI 의장점 Remote objects java.rmi.remote 를확장한 Interface 로선언되어야함 extends java.rmi.remote 모든메소드는 java.rmi.remoteexception 을발생시켜야함 throws java.rmi.remoteexception 1.4
Marshalling Parameters 1.5
원격인터페이스구현 MessageQueueImpl.java MessageQueue.java javac server MessageQueueImpl.class MessageQueueImpl_skel.class rmic MessageQueueImpl_stub.class Factory.java Producer.java Consumer.java javac Factory.class client 1.6
구성 원격인터페이스 : MessageQueue.java 서버프로그램 : MessageQueueImpl.java 클라이언트프로그램 : Factory.java, Producer.java, Consumer.java Policy File : New with Java 2 grant { permission java.net.socketpermission "*:1024-65535","connect,accept"; ; 1.7
실행순서 1. 모든소스파일컴파일 $ javac MessageQueue.java MessageQueueImpl.java Factory.java Producer.java Consumer.java 2. rmic로 stub와 skeleton class 파일생성 $ rmic MessageQueueImpl 3. 레지스트리서비스시작 (rmiregistry) osagent 또는 rpcbind 디몬에해당 $ rmiregistry & (Unix) 또는 C: > start rmiregistry (Windows) 4. 원격서버객체의인스턴스생성 (JDK 1.2 이상버전에서는인증해주어야함 ) $ java -Djava.security.policy=java.policy MessageQueueImpl (JDK 1.2 이상 ) 또는 $ java MessgeQueueImpl (JDK 1.1) 5. 클라이언트에서원격객체실행시작 $ java -Djava.security.policy=java.policy Factory (JDK.2 이상 ) 또는 $ java Factory (JDK 1.1) 1.8
서버 : MessageQueue interface import java.util.*; import java.rmi.*; public interface MessageQueue extends java.rmi.remote { /* * This implements a non-blocking send */ public void send(object item) throws java.rmi.remoteexception; /* * This implements a non-blocking receive */ public Object receive() throws java.rmi.remoteexception; 1.9
서버 : MessageQueueImpl.java (1) import java.util.*; import java.rmi.*; public class MessageQueueImpl extends java.rmi.server.unicastremoteobject implements MessageQueue { public MessageQueueImpl() throws RemoteException { queue = new Vector(); // This implements a non-blocking send public synchronized void send(object item) throws RemoteException { queue.addelement(item); System.out.println("Producer entered " + item + " size = " + queue.size()); 1.10
서버 : MessageQueueImpl.java (2) // This implements a non-blocking receive public synchronized Object receive() throws RemoteException { Object item; if (queue.size() == 0) return null; else { item = queue.firstelement(); queue.removeelementat(0); System.out.println("Consumer removed " + item + " size = " + queue.size()); return item; 1.11
서버 : MessageQueueImpl.java (3) public static void main(string args[]) { System.setSecurityManager(new RMISecurityManager()); try { MessageQueue server = new MessageQueueImpl(); Naming.rebind("//127.0.0.1/MessageServer", server); //Naming.rebind("rmi://media.inchon.ac.kr/MessageServer", server); System.out.println("Server Bound"); catch(exception e) { System.err.println(e); private Vector queue; 1.12
클라이언트 : Factory.java (1) import java.util.*; import java.rmi.*; public class Factory { public Factory() { // remote object MessageQueue mailbox; System.setSecurityManager(new RMISecurityManager()); // install a security manager try { //get a reference to the remote object mailbox = (MessageQueue)Naming.lookup( //127.0.0.1/MessageServer"); //(MessageQueue)Naming.lookup("rmi://media.inchon.ac.kr/MessageServer"); // now create the producer and consumer threads Producer producerthread = new Producer(mailBox); Consumer consumerthread = new Consumer(mailBox); producerthread.start(); consumerthread.start(); catch (Exception e) { System.err.println(e); 1.13
클라이언트 : Factory.java (2) // producer and consumer will call this to nap public static void napping() { int sleeptime = (int) (NAP_TIME * Math.random() ); try { Thread.sleep(sleepTime*1000); catch(interruptedexception e) { public static void main(string args[]) { Factory client = new Factory(); private static final int NAP_TIME = 5; 1.14
클라이언트 : Producer.java import java.util.*; class Producer extends Thread{ public Producer(MessageQueue m) { mbox = m; public void run() { Date message; while (true) { Factory.napping(); // produce an item & enter it into the buffer message = new Date(); try { mbox.send(message); System.out.println( Producer Produced + message); catch (Exception e) { System.err.println(e); private MessageQueue mbox; 1.15
클라이언트 : Consumer.java import java.util.*; class Consumer extends Thread { public Consumer(MessageQueue m) { mbox = m; public void run() { Date message; while (true) { Factory.napping(); // consume an item from the buffer try { message = (Date)mbox.receive(); if (message!= null) // Consume the item System.out.println( Consumer Consumed + message); catch (Exception e) { System.err.println(e); private MessageQueue mbox; 1.16