Java Language
원격 메소드 호출 (RMI)
수색…
비고
RMI에는 클라이언트, 서버 및 공유 원격 인터페이스의 세 가지 구성 요소가 필요합니다. 공유 원격 인터페이스는 서버가 구현해야하는 메소드를 지정하여 클라이언트 - 서버 계약을 정의합니다. 인터페이스는 메소드를 구현할 수 있도록 서버에서 볼 수 있어야합니다. 인터페이스는 클라이언트가 볼 수 있어야 서버가 제공하는 메소드 ( "서비스")를 알 수 있습니다.
원격 인터페이스를 구현하는 모든 객체는 서버의 역할을하도록 예정되어 있습니다. 따라서 서버가 클라이언트의 메소드를 호출 할 수있는 클라이언트 - 서버 관계는 실제로 서버 - 서버 관계입니다. 서버가 "클라이언트"를 콜백 할 수 있기 때문에이를 콜백 이라고합니다. 이를 염두에두고 기능하는 서버에 대해 지정 클라이언트 를 사용할 수 있습니다.
공유 원격 인터페이스는 Remote
확장하는 모든 인터페이스입니다. 서버로 작동하는 객체는 다음을 수행합니다.
-
Remote
를 구현하는UnicastRemoteObject
를 확장하는 것으로, 명시 적 또는 암묵적으로 공유 원격 인터페이스를 구현합니다. -
UnicastRemoteObject
확장하면 암시 적으로 내보내거나UnicastRemoteObject#exportObject
에 전달하여 명시 적으로UnicastRemoteObject#exportObject
있습니다. - 직접 통해서, 레지스트리에 바인더 제본
Registry
또는 간접적 통해Naming
. 이것은, RMI를 통해서 직접적으로 스텁을 전달할 수 있기 때문에, 최초의 통신을 확립하는 경우에만 필요합니다.
프로젝트 설정에서 클라이언트와 서버 프로젝트는 완전히 무관하지만 각 프로젝트는 빌드 경로에 공유 프로젝트를 지정합니다. 공유 프로젝트에는 원격 인터페이스가 포함됩니다.
클라이언트 - 서버 : 다른 JVM에서 메소드를 호출
공유 원격 인터페이스 :
package remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteServer extends Remote {
int stringToInt(String string) throws RemoteException;
}
공유 원격 인터페이스를 구현하는 서버 :
package server;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import remote.RemoteServer;
public class Server implements RemoteServer {
@Override
public int stringToInt(String string) throws RemoteException {
System.out.println("Server received: \"" + string + "\"");
return Integer.parseInt(string);
}
public static void main(String[] args) {
try {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
Server server = new Server();
UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
reg.rebind("ServerName", server);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
서버상의 메소드를 호출하는 클라이언트 (원격) :
package client;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import remote.RemoteServer;
public class Client {
static RemoteServer server;
public static void main(String[] args) {
try {
Registry reg = LocateRegistry.getRegistry();
server = (RemoteServer) reg.lookup("ServerName");
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
Client client = new Client();
client.callServer();
}
void callServer() {
try {
int i = server.stringToInt("120");
System.out.println("Client received: " + i);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
산출:
서버 수신 : "120"
고객 수신 : 120
콜백 : "클라이언트"
개요
이 예에서 클라이언트는 서버를 통해 정보를 서로 보냅니다. 한 클라이언트는 서버에 두 번째 클라이언트로 중계되는 번호를 보냅니다. 두 번째 클라이언트는 수를 반으로 나누고 서버를 통해 첫 번째 클라이언트로 다시 보냅니다. 첫 번째 클라이언트도 똑같이합니다. 서버는 클라이언트 중 하나가 리턴 한 번호가 10보다 작은 경우 통신을 중지합니다. 서버에서 클라이언트로의 리턴 값 (문자열 표현으로 변환 된 번호)은 프로세스를 역 추적합니다.
- 로그인 서버는 자신을 레지스트리에 바인드합니다.
- 클라이언트는 로그인 서버를 찾고 해당 정보로
login
메소드를 호출합니다. 그때:- 로그인 서버는 클라이언트 정보를 저장합니다. 여기에는 콜백 메소드가있는 클라이언트의 스텁이 포함됩니다.
- 로그인 서버는 클라이언트에 저장하고 저장할 서버 스텁 ( "connection"또는 "session")을 작성하여 리턴합니다. 여기에는
logout
메소드 (이 예에서는 사용되지 않음)를 포함한 서버의 스텁이 포함됩니다.
- 클라이언트는 수신자 클라이언트의 이름과
int
하여 서버의passInt
를 호출합니다. - 서버는 해당
int
를 사용하여 수신자 클라이언트의half
을 호출합니다. 이것은 서버에 의해 중단 될 때까지 앞뒤 (콜백 및 콜백) 통신을 시작합니다.
공유 원격 인터페이스
로그인 서버 :
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteLogin extends Remote {
RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}
서버:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteConnection extends Remote {
void logout() throws RemoteException;
String passInt(String name, int i) throws RemoteException;
}
클라이언트 :
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteClient extends Remote {
void half(int i) throws RemoteException;
}
구현
로그인 서버 :
package callbackServer;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
public class LoginServer implements RemoteLogin {
static Map<String, RemoteClient> clients = new HashMap<>();
@Override
public RemoteConnection login(String name, RemoteClient client) {
Connection connection = new Connection(name, client);
clients.put(name, client);
System.out.println(name + " logged in");
return connection;
}
public static void main(String[] args) {
try {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
LoginServer server = new LoginServer();
UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
reg.rebind("LoginServerName", server);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
서버:
package callbackServer;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
public class Connection implements RemoteConnection, Unreferenced {
RemoteClient client;
String name;
public Connection(String name, RemoteClient client) {
this.client = client;
this.name = name;
try {
UnicastRemoteObject.exportObject(this, Registry.REGISTRY_PORT);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void unreferenced() {
try {
UnicastRemoteObject.unexportObject(this, true);
} catch (NoSuchObjectException e) {
e.printStackTrace();
}
}
@Override
public void logout() {
try {
UnicastRemoteObject.unexportObject(this, true);
} catch (NoSuchObjectException e) {
e.printStackTrace();
}
}
@Override
public String passInt(String recipient, int i) {
System.out.println("Server received from " + name + ":" + i);
if (i < 10)
return String.valueOf(i);
RemoteClient client = LoginServer.clients.get(recipient);
try {
client.half(i);
} catch (RemoteException e) {
e.printStackTrace();
}
return String.valueOf(i);
}
}
클라이언트 :
package callbackClient;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
public class Client implements RemoteClient {
RemoteConnection connection;
String name, target;
Client(String name, String target) {
this.name = name;
this.target = target;
}
public static void main(String[] args) {
Client client = new Client(args[0], args[1]);
try {
Registry reg = LocateRegistry.getRegistry();
RemoteLogin login = (RemoteLogin) reg.lookup("LoginServerName");
UnicastRemoteObject.exportObject(client, Integer.parseInt(args[2]));
client.connection = login.login(client.name, client);
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
if ("Client1".equals(client.name)) {
try {
client.connection.passInt(client.target, 120);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void half(int i) throws RemoteException {
String result = connection.passInt(target, i / 2);
System.out.println(name + " received: \"" + result + "\"");
}
}
예제 실행 :
- 로그인 서버를 실행하십시오.
-
Client2 Client1 1097
인수로 클라이언트를 실행하십시오. -
Client1 Client2 1098
인수를 사용하여 클라이언트를 실행하십시오.
3 개의 JVM이 있기 때문에 출력은 3 개의 콘솔에 나타납니다. 여기에 그들은 함께 묶여있다.
로그인 한 Client2
로그인 한 Client1
클라이언트 1에서 수신 한 서버 : 120
Client2로부터받은 서버 : 60
Client1에서받은 서버 : 30
Client2로부터받은 서버 : 15
Client1에서받은 서버 : 7
수신 된 Client1 : "7"
수신 된 Client2 : "15"
수신 된 Client1 : "30"
수신 된 Client2 : "60"
클라이언트 및 서버 구현을 사용한 간단한 RMI 예제
이것은 5 개의 자바 클래스와 2 개의 패키지 인 server 와 client 를 가진 간단한 RMI 예제이다.
서버 패키지
PersonListInterface.java
public interface PersonListInterface extends Remote
{
/**
* This interface is used by both client and server
* @return List of Persons
* @throws RemoteException
*/
ArrayList<String> getPersonList() throws RemoteException;
}
PersonListImplementation.java
public class PersonListImplementation
extends UnicastRemoteObject
implements PersonListInterface
{
private static final long serialVersionUID = 1L;
// standard constructor needs to be available
public PersonListImplementation() throws RemoteException
{}
/**
* Implementation of "PersonListInterface"
* @throws RemoteException
*/
@Override
public ArrayList<String> getPersonList() throws RemoteException
{
ArrayList<String> personList = new ArrayList<String>();
personList.add("Peter Pan");
personList.add("Pippi Langstrumpf");
// add your name here :)
return personList;
}
}
Server.java
public class Server {
/**
* Register servicer to the known public methods
*/
private static void createServer() {
try {
// Register registry with standard port 1099
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
System.out.println("Server : Registry created.");
// Register PersonList to registry
Naming.rebind("PersonList", new PersonListImplementation());
System.out.println("Server : PersonList registered");
} catch (final IOException e) {
e.printStackTrace();
}
}
public static void main(final String[] args) {
createServer();
}
}
클라이언트 패키지
PersonListLocal.java
public class PersonListLocal {
private static PersonListLocal instance;
private PersonListInterface personList;
/**
* Create a singleton instance
*/
private PersonListLocal() {
try {
// Lookup to the local running server with port 1099
final Registry registry = LocateRegistry.getRegistry("localhost",
Registry.REGISTRY_PORT);
// Lookup to the registered "PersonList"
personList = (PersonListInterface) registry.lookup("PersonList");
} catch (final RemoteException e) {
e.printStackTrace();
} catch (final NotBoundException e) {
e.printStackTrace();
}
}
public static PersonListLocal getInstance() {
if (instance == null) {
instance = new PersonListLocal();
}
return instance;
}
/**
* Returns the servers PersonList
*/
public ArrayList<String> getPersonList() {
if (instance != null) {
try {
return personList.getPersonList();
} catch (final RemoteException e) {
e.printStackTrace();
}
}
return new ArrayList<>();
}
}
PersonTest.java
public class PersonTest
{
public static void main(String[] args)
{
// get (local) PersonList
ArrayList<String> personList = PersonListLocal.getInstance().getPersonList();
// print all persons
for(String person : personList)
{
System.out.println(person);
}
}
}
신청서 테스트
- Server.java의 main 메소드를 시작하십시오. 산출:
Server : Registry created.
Server : PersonList registered
- PersonTest.java의 main 메소드를 시작하십시오. 산출:
Peter Pan
Pippi Langstrumpf