JavaRush /Java Blog /Random-IT /RMI: pratica d'uso

RMI: pratica d'uso

Pubblicato nel gruppo Random-IT
Ciao! Oggi esamineremo un argomento piuttosto interessante: l'RMI . Questo sta per Remote Method Invocation . RMI: pratica d'uso - 1Con RMI è possibile insegnare a due programmi a comunicare tra loro, anche se si trovano su computer diversi. Figo? :) Ma non è così difficile da fare! Nella lezione di oggi capiremo in quali parti è composta l'interazione RMI e come configurarla. La prima cosa di cui abbiamo bisogno è un client e un server . Non è necessario approfondire troppo la terminologia informatica. Nel caso di RMI, si tratta semplicemente di due programmi. Uno di essi conterrà un oggetto e il secondo chiamerà i metodi di questo oggetto. Chiamare metodi di un oggetto in un programma che si trova in un altro programma: non l'abbiamo mai fatto prima! È ora di provarlo! :) Per non affogare nella natura selvaggia, lascia che il nostro programma sia semplice. In generale, i server eseguono solitamente alcuni tipi di calcoli richiesti dal client. Per noi sarà lo stesso. Avremo un semplice programma di calcolo come server. Avrà un solo metodo: multiply(). Moltiplicherà i due numeri inviati dal programma client e restituirà il risultato. Innanzitutto abbiamo bisogno di un'interfaccia:
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Perché abbiamo bisogno di un'interfaccia? Il fatto è che il lavoro di RMI si basa sulla creazione di proxy, che hai studiato in una delle lezioni precedenti . E il lavoro con i proxy, come probabilmente ricorderai, viene svolto proprio a livello di interfacce, non di classi. Ci sono 2 requisiti importanti per la nostra interfaccia!
  1. Deve ereditare l'interfaccia del token remoto.
  2. Tutti i suoi metodi devono lanciare una RemoteException (questo non viene fatto automaticamente nell'IDE, devi scriverlo manualmente!).
Ora dobbiamo creare una classe server che implementerà la nostra interfaccia Calculator. RMI: pratica d'uso - 2Anche qui tutto è abbastanza semplice:
import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Non c'è nemmeno molto da commentare qui :) Ora dobbiamo scrivere un programma server che configurerà e avvierà la nostra classe di calcolatrice server. Apparirà così:
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);

   }
}
Scopriamolo :) Nella prima riga creiamo una sorta di variabile stringa:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
Questa stringa è il nome univoco dell'oggetto remoto . Con questo nome il programma client potrà trovare il nostro server: lo vedrai più avanti. Successivamente creiamo il nostro oggetto calcolatrice:
final RemoteCalculationServer server = new RemoteCalculationServer();
Qui è tutto chiaro. Più interessante è quanto segue:
final Registry registry = LocateRegistry.createRegistry(2732);
Questa cosa chiamata Registro è un registro di oggetti cancellati . "Cancellati" non nel senso che li abbiamo cancellati dal computer, ma nel fatto che è possibile accedere agli oggetti di questo registro in remoto da altri programmi :) LocateRegistry.createRegistry()Abbiamo passato al metodo il numero 2732. Questo è il numero di porta. Se non sai cos'è una porta puoi leggerla qui , ma per ora ti basta ricordare che si tratta di un numero univoco attraverso il quale altri programmi possono trovare il nostro registro degli oggetti (vedrai anche questo qui sotto). Andiamo avanti. Vediamo cosa succede nella riga successiva:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
Su questa riga creiamo uno stub . Uno stub incapsula al suo interno l'intero processo di chiamata remota. Si può dire che questo è l'elemento più importante della RMI. Cosa sta facendo?
  1. Riceve tutte le informazioni su una chiamata remota a un metodo.
  2. Se il metodo ha parametri, lo stub li deserializza. Fate attenzione a questo punto! I parametri passati ai metodi per le chiamate remote devono essere serializzabili (dopotutto verranno trasmessi in rete). Non abbiamo questo problema: trasmettiamo solo numeri. Ma se trasferisci oggetti, non dimenticartene!
  3. Successivamente, chiama il metodo desiderato.
Passiamo UnicastRemoteObject.exportObject()il nostro oggetto calcolatore del server al metodo. In questo modo rendiamo possibile richiamare i suoi metodi da remoto. Ci resta solo una cosa da fare:
registry.bind(UNIQUE_BINDING_NAME, stub);
“Registriamo” il nostro stub nel registro degli oggetti remoti con il nome che abbiamo inventato all'inizio. Ora il cliente può trovarlo! Potresti aver notato che alla fine mettiamo in pausa il thread principale del programma:
Thread.sleep(Integer.MAX_VALUE);
Dobbiamo solo mantenere il server in funzione per molto tempo. Eseguiremo due metodi in IDEa contemporaneamente main(): prima quello server (nella classe ServerMainche abbiamo già scritto), e poi quello client (nella classe ClientMainche scriveremo di seguito). È importante che il programma server non si interrompa durante l'avvio del client, quindi lo mettiamo semplicemente in stato di stop per un lungo periodo. Funzionerà comunque :) Ora possiamo eseguire main()il nostro metodo server. Lascialo eseguire e attendi che il programma client chiami qualche metodo :) Ora scriviamo un programma client! Invierà i numeri al nostro server da moltiplicare.
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);
   }
}
Sembra semplice. Cosa sta succedendo qui? Innanzitutto, il client deve essere consapevole del nome univoco dell'oggetto di cui chiamerà i metodi in remoto. Pertanto, nel programma client abbiamo creato anche una variabile, public static final String UNIQUE_BINDING_NAME = "server.calculator"; successivamente nel metodo main()otteniamo l'accesso al registro degli oggetti remoti. Per fare ciò, dobbiamo chiamare il metodo LocateRegistry.getRegistry()e passare lì il numero di porta su cui è stato creato il nostro registro nel programma ServerMain - porta 2732 (questo numero è stato scelto per l'esempio, puoi provare ad usarne un altro):
final Registry registry = LocateRegistry.getRegistry(2732);
Ora non ci resta che prelevare dalla cassa l'oggetto desiderato! È facile perché conosciamo il suo nome univoco!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Presta attenzione al casting del tipo. Trasformiamo l'oggetto risultante in un'interfaccia Calculatoranziché in una classe concreta RemoteCalculationServer . Come abbiamo detto all'inizio della lezione, RMI si basa sull'uso di un proxy, quindi la chiamata remota è disponibile solo per i metodi delle interfacce, non per le classi. Alla fine, chiamiamo in remoto un metodo multiply()sul nostro oggetto e stampiamo il risultato sulla console.
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
Abbiamo lanciato il metodo main()in classe ServerMainmolto tempo fa, è ora di lanciare il metodo main()nel programma client ClientMain! Uscita console: 600 Questo è tutto! Il nostro programma (anche due!) ha svolto con successo la sua funzione :) Se hai tempo e voglia, puoi diversificarlo un po'. Ad esempio, assicurati che la calcolatrice supporti tutte e quattro le operazioni standard e che non vengano passati i numeri, ma un oggetto come parametri CalculationInstance(int x, int y). Come materiale aggiuntivo, puoi consultare articoli ed esempi - qui: Ci vediamo alle prossime lezioni! :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION