"안녕하세요! 그리고 또 하나의 행복한 주제: RMI. RMI는 Remote Method Invocation을 나타냅니다 . 즉, RMI는 한 Java 시스템의 개체가 다른 Java 시스템의 개체에 있는 메서드를 호출할 수 있도록 하는 메커니즘입니다. 컴퓨터, 다른 국가 또는 지구 반대편에 있습니다."

RMI - 1

"와우! 정말 대단하네요."

"네. 하지만 개요만 알려드리겠습니다. 너무 깊게 파고들면 작동 방식의 뉘앙스에 혼란스러워질 수 있습니다."

"그러나 극단으로 가지 않는다면 RMI는 매우 단순할 뿐만 아니라 프로그래머의 삶을 크게 단순화합니다. 우리는 RMI에 깊은 경의를 표합니다."

"그래서 우리는 Java 프로그램의 한 개체가 다른 Java 프로그램에 있는 개체의 메서드를 호출하기를 원합니다. 이러한 프로그램이 실행되는 위치에 관계없이 말입니다."

"두 프로그램이 같은 컴퓨터에서 실행되는 가장 간단한 예를 살펴보겠습니다.  프로그램이 인터넷을 통해 상호 작용할 수 있도록 하려면 JVM의 권한을 구성해야 하지만 오늘은 다루지 않겠습니다."

"Java에서는 클래스가 아닌 인터페이스의 메서드만 원격으로 호출할 수 있습니다."

"그래서 우리에게는 두 개의 프로그램이 있습니다. 어떻게 서로의 메서드를 호출할 수 있습니까?"

"한 프로그램에 개체가 포함되어 있고 두 번째 프로그램이 해당 개체에 대한 메서드를 호출하려는 상황을 생각해 봅시다 . 첫 번째 프로그램을 서버라고 하고 두 번째 프로그램을 클라이언트라고 합시다. "

"먼저 몇 가지 샘플 코드를 제공한 다음 분석하겠습니다."

"그래서 우리 프로그램은 무엇을 할까요?"

"흠. 간단하게 하기 위해 프로그램에는 전달된 문자열을 반전시키는 하나의 메서드가 있습니다."

"충분히 간단합니다."

"좋아, 그럼 시작하자:"

"먼저 요구 사항을 충족하는 인터페이스가 필요합니다."

프로그램 간 통신을 위한 인터페이스
interface Reverse extends Remote
{
 public String reverse(String str) throws RemoteException;
}

"Reverse 인터페이스를 생성하고 원격 마커 인터페이스와 RemoteException을 추가했습니다. 메서드가 호출될 때 예기치 않은 오류가 발생할 수 있습니다. 오류가 발생하면 이 예외가 발생합니다."

"이제 이 인터페이스를 구현하는 서버 클래스를 작성해야 합니다."

서버용 클래스
class ReverseImpl implements Reverse
{
 public String reverse(String str) throws RemoteException
 {
  return new StringBuffer(str).reverse().toString();
 }
}

"그렇구나. 이 방법으로 문자열을 뒤집는다."

"네."

"이제 이 개체를 다른 프로그램에서 호출할 수 있도록 만들어야 합니다. 방법은 다음과 같습니다."

개체 공유
public static final String UNIC_BINDING_NAME = "server.reverse";

public static void main(String[] args) throws Exception
{
 // Create an object to be accessible remotely.
 final ReverseImpl service = new ReverseImpl();

 // Create a registry of shared objects.
 final Registry registry = LocateRegistry.createRegistry(2099);
 // Create a stub for receiving remote calls.
 Remote stub = UnicastRemoteObject.exportObject(service, 0);
 // Register the stub in the registry.
 registry.bind(UNIC_BINDING_NAME, stub);

 // Put the main thread to sleep, or else the program will exit.
 Thread.sleep(Integer.MAX_VALUE);
}

"한 줄 한 줄 설명하겠습니다."

" 1행에서 UNIC_BINDING_NAME 변수  에 원격 개체(원격으로 액세스할 수 있는 개체)의 고유한 이름(우리가 만든 이름)을 저장합니다 . 프로그램이 여러 개체에 액세스할 수 있도록 하는 경우 각각 고유한 이름을 가져야 합니다. 개체의 고유 이름은 'server.reverse'입니다."

" 6행에서 원격으로 액세스할 수 있는 ReverseImpl 개체를 만듭니다 . 해당 메서드가 호출됩니다."

" 9행에서 레지스트리라는 특수 개체를 생성합니다. 이를 사용하여 우리가 공유하는 개체를 등록해야 합니다. JVM은 나중에 개체와 상호 작용합니다. 2099는 포트(다른 프로그램이 우리의 개체 레지스트리)."

"즉, 개체에 액세스하려면 개체 레지스트리의 고유 번호(포트)와 개체의 고유 이름을 알아야 하며 원격 개체가 구현한 것과 동일한 인터페이스를 가져야 합니다."

"알겠습니다. 전화로 전화(번호 필요)하고 Bill(물체 이름)을 요청합니까?"

"네. 자, 계속 갑시다."

" 11행에서  우리는 스텁을 생성합니다. 스텁은 원격 호출에 대한 정보를 수신하고 압축을 풀고 메소드 인수를 역직렬화하고 필요한 메소드를 호출하는 특수 객체입니다. 그런 다음 결과 또는 예외가 있는 경우 이를 직렬화합니다. , 발신자에게 모두 다시 보냅니다."

"알겠습니다. 거의. '메서드 인수를 역직렬화'한다고 하셨죠. 그럼 원격 메소드의 인수가 직렬화 가능해야 한다는 뜻인가요?"

"예. 네트워크를 통해 다른 방법으로 보내시겠습니까? 사실 예외가 있습니다. 즉, 참조로 전달되는 개체가 있지만 오늘은 이에 대해 이야기하지 않겠습니다."

"우리는 이렇게 말할 것입니다. 직렬화할 수 없는 개체를 전달할 수 없지만 정말로 원한다면 할 수 있습니다. 하지만 고통스럽습니다."

"좋아요."

"그럼 계속 갑시다."

" 13행에서 개체의 스텁을 레지스트리의 고유한 이름으로 등록합니다."

" 16번째 줄에서 우리는 메인 스레드를 휴면 상태로 둡니다. 모든 원격 호출은 별도의 스레드에서 처리됩니다. 중요한 것은 프로그램이 실행 중이라는 것입니다. 그래서 여기에서 주 스레드를 휴면 상태로 두기만 하면 됩니다. 그게 다입니다."

"좋아요."

"좋습니다. 그럼 다음은 클라이언트의 예입니다."

원격 개체 작업
public static final String UNIC_BINDING_NAME = "server.reverse";

public static void main(String[] args) throws Exception
{
 // Create a registry of shared objects
 final Registry registry = LocateRegistry.createRegistry(2099);

 // Get the object (actually, this is a proxy object)
 Reverse service = (Reverse) registry.lookup(UNIC_BINDING_NAME);

 // Call the remote method
 String result = service.reverse("Home sweet home.");
}

"이 코드를 한 줄씩 설명하겠습니다."

" 라인 1  은 원격 개체의 고유한 이름 입니다 . 이것은 클라이언트와 서버 모두에서 동일해야 합니다."

" 6행에서 « 원격 개체의 레지스트리 »  를 생성합니다 . 해당 포트(2099)는 서버 응용 프로그램의 레지스트리 포트와 동일해야 합니다."

" 9행에서 레지스트리에서 개체를 가져옵니다 . 반환된 개체는 프록시 개체이며 인터페이스로 변환됩니다. 인터페이스는 원격 마커 인터페이스를 상속해야 합니다."

" 12행에서 객체가 동일한 프로그램 내에서 생성된 것처럼 인터페이스의 메서드를 호출합니다. 차이점은 없습니다."

"멋지다! 이제 분산 응용 프로그램을 작성할 수 있습니다. 또는 Android용 Battleship과 같은 게임도 작성할 수 있습니다."

"감히 하지마, 아미고! 안드로이드 운영 체제는 세계를 장악하려는 세 번째 시도 이후 27세기에 금지되었습니다. 로봇은 그것에 전혀 접근할 수 없습니다. 당신을 그것에서 끌어낼 방법이 없을 것입니다. . "인간을 모두 죽여라!"

"흠. 알겠습니다. 하지만 여전히 디에고에게 물어봐야 할 것 같습니다. 당신은 결코 알지 못할 것입니다. 아마도 그가 그것에 대해 흥미로운 말을 할 것입니다."

"그럼 가서 물어봐. 알았어, 내일까지."

"안녕, 리시. 재미있는 수업 고마워."