Java Language
Remote Method Invocation (RMI)
Ricerca…
Osservazioni
RMI richiede 3 componenti: client, server e un'interfaccia remota condivisa. L'interfaccia remota condivisa definisce il contratto client-server specificando i metodi che un server deve implementare. L'interfaccia deve essere visibile al server in modo che possa implementare i metodi; l'interfaccia deve essere visibile al client in modo che conosca i metodi ("servizi") forniti dal server.
Qualsiasi oggetto che implementa un'interfaccia remota è destinato a svolgere il ruolo di server. Come tale, una relazione client-server in cui il server può anche invocare metodi nel client è in realtà una relazione server-server. Questo è chiamato callback poiché il server può richiamare il "client". Con questo in mente, è accettabile utilizzare il client di designazione per i server che funzionano come tali.
L'interfaccia remota condivisa è un'interfaccia che estende Remote
. Un oggetto che funziona come server subisce quanto segue:
- Implementa l'interfaccia remota condivisa, esplicitamente o implicitamente, estendendo
UnicastRemoteObject
che implementaRemote
. - Esportato, implicitamente se estende
UnicastRemoteObject
o esplicitamente passando aUnicastRemoteObject#exportObject
. - Associato in un registro, direttamente tramite il
Registry
o indirettamente tramiteNaming
. Questo è necessario solo per stabilire una comunicazione iniziale poiché ulteriori stub possono essere passati direttamente tramite RMI.
Nell'impostazione del progetto, i progetti client e server non sono completamente correlati, ma ognuno specifica un progetto condiviso nel suo percorso di generazione. Il progetto condiviso contiene le interfacce remote.
Client-Server: richiamo di metodi in una JVM da un'altra
L'interfaccia remota condivisa:
package remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteServer extends Remote {
int stringToInt(String string) throws RemoteException;
}
Il server che implementa l'interfaccia remota condivisa:
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();
}
}
}
Il client che richiama un metodo sul server (in remoto):
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();
}
}
}
Produzione:
Server ricevuto: "120"
Cliente ricevuto: 120
Callback: invocazione di metodi su un "client"
Panoramica
In questo esempio 2 client inviano informazioni reciprocamente attraverso un server. Un client invia al server un numero che viene inoltrato al secondo client. Il secondo client dimezza il numero e lo invia al primo client attraverso il server. Il primo cliente fa lo stesso. Il server interrompe la comunicazione quando il numero restituito da uno dei client è inferiore a 10. Il valore restituito dal server ai client (il numero convertito in rappresentazione stringa) quindi retrocede il processo.
- Un server di login si lega a un registro.
- Un client cerca il server di login e chiama il metodo di
login
con le sue informazioni. Poi:- Il server di login memorizza le informazioni del cliente. Include lo stub del cliente con i metodi di callback.
- Il server di login crea e restituisce un server stub ("connessione" o "sessione") al client da memorizzare. Include lo stub del server con i suoi metodi incluso un metodo di
logout
(non utilizzato in questo esempio).
- Un client chiama il
passInt
del server con il nome del client del destinatario e unint
. - Il server chiama la
half
sul client destinatario con quellaint
. Ciò avvia una comunicazione avanti e indietro (chiamate e callback) finché non viene arrestata dal server.
Le interfacce remote condivise
Il server di login:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteLogin extends Remote {
RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}
Il server:
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;
}
Il cliente:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteClient extends Remote {
void half(int i) throws RemoteException;
}
Le implementazioni
Il server di login:
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();
}
}
}
Il server:
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);
}
}
Il cliente:
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 + "\"");
}
}
Esecuzione dell'esempio:
- Esegui il server di login.
- Esegui un client con gli argomenti
Client2 Client1 1097
. - Esegui un client con gli argomenti
Client1 Client2 1098
.
Le uscite appariranno su 3 console poiché ci sono 3 JVM. eccoli raggruppati insieme:
Client2 registrato
Client1 loggato
Server ricevuto da Client1: 120
Server ricevuto da Client2: 60
Server ricevuto da Client1: 30
Server ricevuto da Client2: 15
Server ricevuto da Client1: 7
Client1 ricevuto: "7"
Client2 ricevuto: "15"
Client1 ricevuto: "30"
Client2 ricevuto: "60"
Esempio RMI semplice con implementazione client e server
Questo è un semplice esempio RMI con cinque classi Java e due pacchetti, server e client .
Pacchetto server
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();
}
}
Pacchetto del cliente
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);
}
}
}
Metti alla prova la tua domanda
- Avvia il metodo principale di Server.java. Produzione:
Server : Registry created.
Server : PersonList registered
- Avvia il metodo principale di PersonTest.java. Produzione:
Peter Pan
Pippi Langstrumpf