John Squirrels
레벨 41
San Francisco

자바 RMI

무작위의 그룹에 게시되었습니다
안녕! 오늘 우리는 다소 흥미로운 주제인 Java RMI를 고려할 것입니다. 이것은 Remote Method Invocation의 약자입니다. RMI를 사용하여 두 프로그램이 서로 다른 컴퓨터에 있더라도 서로 통신할 수 있습니다. 멋있게 들리나요? :) 그리고 그렇게 어렵지 않습니다! 오늘 수업에서는 RMI 상호 작용의 요소를 분석하고 이를 구성하는 방법을 알아봅니다. 가장 먼저 필요한 것은 클라이언트와 서버입니다. 우리는 컴퓨터 용어에 깊이 빠져들 필요가 없습니다. RMI와 관련하여 이들은 두 가지 프로그램에 불과합니다. 그 중 하나는 개체를 포함하고 다른 하나는 해당 개체의 메서드를 호출합니다. 다른 프로그램에 존재하는 객체의 메서드 호출 — 이제 우리가 아직 하지 않은 일입니다! 시도해 볼 시간입니다! :) 수렁에 빠지지 않으려면 프로그램을 단순하게 유지합니다. 일반적으로 서버는 클라이언트가 요청한 일부 계산을 수행합니다. 그리고 그것은 우리와 함께 할 것입니다. 우리 서버는 간단한 계산기 프로그램입니다. 하나의 방법만 있습니다.곱하기() . 클라이언트 프로그램이 보낸 두 개의 숫자를 곱한 다음 결과를 반환합니다. 우선 인터페이스가 필요합니다.

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
인터페이스가 필요한 이유는 무엇입니까? RMI는 이전 단원 에서 학습한 프록시 생성에 의존하기 때문입니다 . 기억하시겠지만 우리는 클래스가 아닌 인터페이스를 통해 프록시를 사용합니다. 인터페이스에는 2가지 중요한 요구 사항이 있습니다!
  1. 원격 인터페이스를 확장해야 합니다.
  2. 모든 메서드는 RemoteException을 발생시켜야 합니다(IDE는 이를 자동으로 수행하지 않습니다. 수동으로 추가해야 합니다!).
이제 계산기 인터페이스 를 구현하는 서버 클래스를 만들어야 합니다 . 실제 RMI - 2여기에서도 모든 것이 매우 간단합니다.

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
여기에는 언급할 내용이 없습니다. :) 이제 계산기 개체를 구성하고 실행할 서버 프로그램을 작성해야 합니다. 다음과 같이 표시됩니다.

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
알아봅시다 :) 첫 번째 줄에서 일부 String 변수를 선언합니다.

public static final String UNIQUE_BINDING_NAME = "server.calculator";
이 문자열은 원격 개체의 고유한 이름입니다. 클라이언트 프로그램은 이 이름을 사용하여 서버를 찾습니다. 나중에 보게 될 것입니다. 다음으로 계산기 개체를 만듭니다.

final RemoteCalculationServer server = new RemoteCalculationServer();
여기서 모든 것이 명확합니다. 다음에 오는 것은 더 흥미 롭습니다.

final Registry registry = LocateRegistry.createRegistry(2732);
이 레지스트리 개체는 원격 개체의 레지스트리입니다. 다른 프로그램이 원격으로 접근할 수 있는 객체들입니다 :) LocateRegistry.createRegistry() 메서드 에 2732라는 숫자를 전달했습니다 . 이것은 포트 번호입니다. 다른 프로그램에서 개체 레지스트리를 찾는 데 사용할 고유 번호입니다(다시 말하지만 아래에서 확인할 수 있음). 바로 이동... 다음 줄에서 어떤 일이 발생하는지 봅시다.

Remote stub = UnicastRemoteObject.exportObject(server, 0);
이 줄에 스텁을 만듭니다. 스텁은 전체 원격 호출을 캡슐화합니다. 이것은 RMI의 가장 중요한 요소라고 볼 수 있습니다. 무엇을합니까?
  1. 일부 메소드의 원격 호출에 대한 모든 정보를 수신합니다.
  2. 메소드에 매개변수가 있으면 스텁이 매개변수를 역직렬화합니다. 이 점에 주목하세요! 원격으로 호출되는 메서드에 전달하는 인수는 직렬화 가능해야 합니다(결국 네트워크를 통해 전송됨). 이것은 우리에게 문제가 되지 않습니다. 우리는 단지 숫자를 전송하는 것입니다. 그러나 개체를 전송하는 경우 이 요구 사항을 잊지 마십시오!
  3. 그런 다음 스텁이 원하는 메서드를 호출합니다.
계산기 서버 개체를 UnicastRemoteObject.exportObject() 메서드에 전달합니다. 이것이 우리가 그 메서드를 원격으로 호출할 수 있게 하는 방법입니다. 할 일이 하나 남았습니다.

registry.bind(UNIQUE_BINDING_NAME, stub);
처음에 만든 이름으로 원격 개체 레지스트리에 스텁을 "등록"합니다. 이제 고객이 찾을 수 있습니다! 아마도 당신은 우리가 프로그램의 메인 스레드를 마지막에 잠들게 한다는 것을 알아차렸을 것입니다:

Thread.sleep(Integer.MAX_VALUE);
서버가 오랫동안 실행되기만 하면 됩니다. IDE에서 두 가지 main() 메서드를 동시에 시작합니다. 첫 번째는 서버의 main() 메서드( 이미 작성한 ServerMain 클래스에 있음)와 두 번째는 클라이언트의 main() 메서드( ClientMain 클래스에 있음)입니다. 아래에 작성하겠습니다). 우리가 클라이언트를 시작하는 동안 서버 프로그램이 종료되지 않는 것이 중요합니다. 어떤 경우에도 계속 실행됩니다 :) 이제 서버의 main() 메서드를 실행할 수 있습니다. 실행하고 클라이언트 프로그램이 어떤 메서드를 호출할 때까지 기다립니다 :) 이제 클라이언트 프로그램을 작성해 봅시다! 곱셈을 위해 서버에 숫자를 보냅니다.

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
간단해 보인다. 하지만 여기서 무슨 일이 일어나고 있습니까? 첫째, 클라이언트는 원격으로 호출할 메서드의 고유한 이름을 알아야 합니다. 따라서 클라이언트 프로그램에서 public static final String UNIQUE_BINDING_NAME = "server.calculator"; 변하기 쉬운. 다음으로 main() 메서드에서 원격 개체의 레지스터에 액세스합니다. 이렇게 하려면 LocateRegistry.getRegistry() 메서드를 호출하고 ServerMain 프로그램에서 레지스트리를 만드는 데 사용되는 포트 번호를 전달해야 합니다(포트 2732; 이 번호는 예시일 뿐이며 다른 번호를 사용해 볼 수 있습니다).

final Registry registry = LocateRegistry.getRegistry(2732);
이제 레지스트리에서 원하는 개체를 가져오기만 하면 됩니다! 고유한 이름을 알고 있기 때문에 쉽습니다!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
타입 캐스팅에 주의하세요. 수신된 개체를 RemoteCalculationServer 클래스 가 아닌 Calculator 인터페이스 로 캐스팅합니다 . 수업 시작 부분에서 말했듯이 RMI는 프록시에 의존하므로 원격 호출은 클래스의 메서드가 아닌 인터페이스의 메서드에서만 사용할 수 있습니다. 마지막으로 객체에 대한 multiply() 메서드를 원격으로 호출 하고 결과를 콘솔에 출력합니다.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
ServerMain 클래스의 main () 메서드는 이미 오랫동안 실행되었습니다. 이제 클라이언트 프로그램( ClientMain )에서 main() 메서드를 실행할 차례입니다 ! 콘솔 출력:

600
그게 다야! 우리 프로그램(실제로는 두 개의 프로그램!)이 해야 할 일을 했습니다 :) 시간과 욕구가 있다면 이것을 조금 더 꾸밀 수 있습니다. 예를 들어 계산기가 네 가지 표준 산술 연산을 지원하도록 만들고 숫자를 기본 유형이 아닌 CalculationInstance(int x, int y) 개체로 전달합니다. 다음 강의에서 만나요! :)
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION