728x90


안녕하세요. 공유민입니다.

지난 편에 이어서 RMI 프로그래밍에 대해 알아보겠습니다.






Java RMI, Java Remote Method Invocation
(
자바 원격 함수 호출)




2. Java RMI 프로그래밍



2.1 Java RMI 구성



위 그림처럼 서버 쪽 PC에는 공통인터페이스, 구현클래스, 스켈레톤(스텁) 클래스, 서버실행 클래스가 필요하고

클라이언트 쪽 PC에는 공통인터페이스, 스텁 클래스, 클라이언트 실행 클래스가 필요합니다.



2.2 Server 프로그래밍



- 공통 인터페이스

          

1
2
3
      4
5
6
7
8
9
 // SampleI.java
 package gym.dev;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
 public interface SampleI extends Remote 
 {
     int     Add(int num1, int num2)  throws RemoteException;
     String  Echo(String Msg)  throws RemoteException;    
 }
cs

Server 쪽 프로그래밍을 해보겠습니다. 현재 보시는 코드는 인터페이스 입니다.

클라이언트의 객체가 서버의 객체가 갖고 있는 메소드를 부를 때, 이 인터페이스를 사용하여 부르게 됩니다

인터페이스는 클라이언트와 서버 모두 같은 것을 갖고 있어야 합니다. 패키지명은 gym.dev로 하였습니다

주의할 점은 패키지명은 클라이언트와 서버, 인터페이스 모두 동일하게 사용하여야 합니다

한가지 더 봐야할 점은든 원격 인터페이스는 Remote 클래스를 상속하여야 하고 선언되는 메소드들은 모두 RemoteException 예외 클래스를 던져야 합니다그래야만 통신을 할 수 있습니다서버에 구현하는 메소드는 간단하게 덧셈을 하는 Add 메소드와 입력된 값을 되돌려주는 Echo 메소드를 구현하였습니다



- 구현 클래스 & 스켈레톤 클래스 & 서버 실행 클래스

1
2
3
4
   5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 // Server.java
 package gym.dev;
        
 import java.rmi.registry.Registry;
 import java.rmi.registry.LocateRegistry;
 import java.rmi.RemoteException;
 import java.rmi.server.UnicastRemoteObject;
        
 public class Server implements SampleI {
        
     public Server() {}
  
     // 함수 구현
     public String Echo(String Msg) {
         return Msg;
     }
 
     public int Add(int num1, int num2) {
             int sum = num1 + num2;
         return sum;
     }
 
     // 서버 실행 메인
     public static void main(String args[]) {
        
         try {
                         
             // 원격 객체를 export하여 통시하는 stub를 생성 및 접속할 수 있게끔 한다.
             Server obj = new Server();
             SampleI stub = (SampleI) UnicastRemoteObject.exportObject(obj, 0);
 
             // RMI registry에 원격 객체(인터페이스가 상속)의 stub을 gongyumin와 bind 한다.
             Registry registry = LocateRegistry.getRegistry();
             registry.bind("gongyumin", stub);
            
             // 서버 준비 완료
             System.err.println("Server ready");
         } catch (Exception e) {
             System.err.println("Server exception: " + e.toString());
             e.printStackTrace();
         }
     }
 }
cs


서버 클래스를 프로그래밍 하겠습니다.

우선 Server.java 파일에 방금 만들었던 SampleI 인터페이스를 Server.java에 구현합니다.

그리고 인터페이스 함수들을 구현할 때에는 RemoteException 객체를 던지지 않아도 됩니다

왜냐하면 인터페이스에서 이미 RemoteException을 throw로 처리했기 때문에 사용하는 클라이언트 쪽에서 예외를 처리해 주어야 합니다.


그리고 main 함수를 살펴보면, 29~30라인에서 서비스를 공급하는 원격 객체를 생성합니다

그리고 원격 객체는 Java RMI Runtime으로 export되어야 합니다. 이 과정을 통해 stub이 만들어 집니다.

위 코드에서 만들어진 서버 측 stub을 클라이언트에서 찾을 수 있도록 RMI registry등록해주어야합니다

그 부분을 수행하는 코드는 33~34라인 입니. 이 부분에 설명드리고 넘어가겠습니다. 이 부분에 LocateRegistry.getRegistry() 함수는 오버로딩 되어 있어서 인자가 없이 호출 된다면, 디폴트 포트인 1099를 사용하고, 포트를 설정하고 싶다면 숫자 값을 넣어줄 수 있습니다

아래에서 클라이언트에서도 이 함수를 사용할 때, 다시 설명드리겠습니다.

그리고 아랫 줄에서 gongyumin라는 이름으로 bind하여 stub , 원격 객체를 등록합니다.



2.3 Client(User 포함) 프로그래밍



- 스텁 클래스 & 클라이언트 실행 클래스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
     21
22
23
24
25
26
27
28
// Client.java
package gym.dev;
 
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
     public static void main(String[] args) {
 
        String host = (args.length < 1) ? null : args[0];
        try {
            // Rmi registry에 서버 IP, port를 설정한다.
            Registry registry = LocateRegistry.getRegistry(host);
            
            // Rmi registry.lookup을 통해 gongyumin이름을 찾아 stub을 가져온다.
            SampleI stub = (SampleI) registry.lookup("gongyumin");
            
            // server의 함수를 호출한다.
            String ResultEcho   = stub.Echo("Hello World");
            int    ResultAdd    = stub.Add(125175);
            
            System.out.println("ResultEcho  : " + ResultEcho);
            System.out.println("ResultAdd   : " + ResultAdd);            
        } catch (Exception e) {
            System.err.println("Client exception: " + e.toString());
            e.printStackTrace();
        }
    }
}
cs


이어서 Client 쪽 프로그래밍에 대해 설명 드리겠습니다

Client2가지로 방법으로 나눠서 ClientUser까지 포함한 것과 분리된 것으로 나눠 설명하겠습니다

여기서 Client만을 의미하는 것은 스텁클래스를 뜻합니다

User가 뜻하는 것은 서버 쪽 메소드를 호출하고 리턴된 결과 값을 사용하는 사용자를 뜻합니다.

우선 ClientUser가 포함된 케이스에 대해 설명 드리겠습니다. 클라이언트 측에도 서버 쪽과 같은 인터페이스 파일이 필요합니다. 하지만, 인터페이스 파일은 서버에서 만들었던 것이 있기에 프로그래밍 설명은 생략하겠습니다.

다음으로 Clinet.java를 설명하겠습니다.

15 라인을 보시면, Server쪽에서 보셨던 LocateRegistry.getRegistry() 함수입니다

오버로딩이 되어 있기 떄문에, 서버 측의 IP와 포트번호를 적어줍니다

이 역시 디폴트 시, localhost를 사용하고 포트는 1099를 사용합니다.

그 후에, 18라인에서 gongyuminlookup하여 stub을 찾아오면 연결이 된 것 입니다.

21~22라인을 보면, 서버의 메소드를 stub을 통하여 호출할 수 있습니다.



2.4 Client, User 프로그래밍


- 스텁 클래스


1
2
3
4
5
6
7
8
 9
10
     11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Client.java
    // 패키지 및 생성자 중략…
    public String CallClientEcho ( String host, 
                                   int port, 
                                   String Msg
                                   ) 
    {
        try {
            // Rmi registry에 서버 IP, port를 설정한다.
            Registry registry = LocateRegistry.getRegistry(host, port);
            
            // Rmi registry.lookup을 통해 gongyumin이름을 찾아 stub을 가져온다.
            SampleI stub = (SampleI) registry.lookup("gongyumin");
            
            // server의 Echo 함수를 호출한다.
            String ResultEcho   = stub.Echo(Msg);
            
            // User에게 결과 값 리턴
            return ResultEcho;  
        } catch (Exception e) {
            return "Occur Exception";
        }
    }    
}
cs


이번에는 ClientUser를 구분하려 프로그래밍 해보겠습니다.

먼저 스텁 클래스인 Client.java를 보겠습니다.

앞에서 설명했던 10라인, 13라인, 16라인은 3부분은 변하지 않았습니다

하지만User가 호출 할 메소드를 생성합니다

파라미터로는 IP, Port번호를 받고 서버로부터 받은 결과 값은 리턴해 줍니다.

현재 소스에서는 echo함수만 보이지만 add 함수는 소스가 중복되는 부분이 많아 생략하였습니다.



- 클라이언트 실행 클래스


1
2
3
4
5
6
7
8
9
10
11
12
13
     14
15
16
17
18
19
20
21
22
23
24
25
import gym.dev.Client;
 
public class User 
{
    private User() {}
 
    public static void main(String[] args) 
    {
        String host = (args.length < 1) ? null : args[0];
        if (host == null)
        {
            host = "localhost";     // 또는 "127.0.0.1"
        }
        int port = 1099;
                
        // Client 객체 선언
        Client client = new Client();                
        
        String EchoResult = client.CallClientEcho(host, port, "Hello World!");
        int    AddResult  = client.CallClientAdd(host, port, 125175);
                
        System.out.println("EchoResult  : " + EchoResult);        
        System.out.println("AddResult   : " + AddResult);                    
    }        
}
cs



이번에는 실행 클래스인 User 부분 프로그래밍 부분입니다.

17~ 20 라인 처럼 Client classimport 하고, Client를 객체 선언 후, 호출하여 사용하면 됩니다.




다음 포스팅에는 Java RMI를 실행하는 커맨드와 테스트를 게시하겠습니다.

감사합니다.









'개발 > Java RMI' 카테고리의 다른 글

Java RMI, #3 Java RMI 실행하기  (0) 2017.02.22
Java RMI, #1 Java RMI란?  (0) 2017.02.21

+ Recent posts