John Squirrels
Niveau 41
San Francisco

Java-RMI

Gepubliceerd in de groep Willekeurig
Hoi! Vandaag zullen we een nogal interessant onderwerp bekijken: Java RMI. Dit staat voor Remote Method Invocation. U kunt RMI gebruiken om twee programma's met elkaar te laten communiceren, zelfs als ze zich op verschillende computers bevinden. Klinkt dat cool? :) En het is niet zo moeilijk om te doen! In de les van vandaag analyseren we de elementen van de RMI-interactie en zoeken we uit hoe we deze kunnen configureren. Het eerste wat we nodig hebben is een client en een server. We hoeven niet echt diep in de computerterminologie te duiken. Als het op RMI aankomt, zijn dit slechts twee programma's. Een van hen zal een object bevatten en de andere zal methoden op dat object aanroepen. Methoden aanroepen van een object dat in een ander programma bestaat — dat hebben we nog niet gedaan! Het is tijd om het eens te proberen! :) Laten we, om te voorkomen dat we vastlopen s houden ons programma eenvoudig. Over het algemeen voert een server enkele berekeningen uit die door een client zijn aangevraagd. En zo zal het ook met ons zijn. Onze server zal een eenvoudig rekenprogramma zijn. Het heeft maar één methode:vermenigvuldigen() . Het vermenigvuldigt twee getallen die door het clientprogramma zijn verzonden en retourneert vervolgens het resultaat. Allereerst hebben we een interface nodig:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Waarom hebben we een interface nodig? Omdat RMI afhankelijk is van het maken van proxy's, die u in eerdere lessen hebt bestudeerd . Zoals je je waarschijnlijk herinnert, werken we met proxy's via interfaces, niet met klassen. Er zijn 2 belangrijke vereisten voor onze interface!
  1. Het moet de externe interface uitbreiden.
  2. Alle methoden moeten een RemoteException genereren (de IDE doet dit niet automatisch - u moet dit handmatig toevoegen!).
Nu moeten we een serverklasse maken die onze Calculator- interface implementeert. RMI in de praktijk - 2Ook hier is alles vrij eenvoudig:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Er is hier niet echt iets om op te reageren :) Nu moeten we een serverprogramma schrijven dat ons rekenmachine-object zal configureren en uitvoeren. Het zal er zo uitzien:

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);

   }
}
Laten we dit uitzoeken :) In de eerste regel declareren we een String-variabele:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Deze tekenreeks is de unieke naam van het object op afstand. Ons clientprogramma gebruikt deze naam om onze server te vinden: u zult dit later zien. Vervolgens maken we ons rekenmachine-object:

final RemoteCalculationServer server = new RemoteCalculationServer();
Alles is hier duidelijk. Wat daarna komt is interessanter:

final Registry registry = LocateRegistry.createRegistry(2732);
Dit registerobject is een register van externe objecten. Dit zijn objecten waartoe andere programma's op afstand toegang hebben :) We hebben het nummer 2732 doorgegeven aan de methode LocateRegistry.createRegistry() . Dit is het poortnummer — een uniek nummer dat andere programma's zullen gebruiken om ons objectregister te vinden (nogmaals, u zult dit hieronder zien). We gaan verder... Laten we eens kijken wat er in de volgende regel gebeurt:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
We maken een stomp in deze regel. Een stub kapselt het volledige externe gesprek in. U kunt dit beschouwen als het belangrijkste element van RMI. Wat doet het?
  1. Het ontvangt alle informatie over een oproep op afstand van een of andere methode.
  2. Als de methode parameters heeft, zal de stub ze deserialiseren. Let op dit punt! De argumenten die u doorgeeft aan de op afstand aangeroepen methoden moeten kunnen worden geserialiseerd (ze worden immers via het netwerk verzonden). Dit is geen probleem voor ons - we sturen alleen cijfers door. Maar vergeet deze vereiste niet als u objecten verzendt!
  3. Daarna roept de stub de gewenste methode aan.
We geven ons rekenmachineserverobject door aan de methode UnicastRemoteObject.exportObject() . Zo maken we het mogelijk om op afstand zijn methodes aan te roepen. Er zit nog maar één ding op:

registry.bind(UNIQUE_BINDING_NAME, stub);
We "registreren" onze stub in het objectregister op afstand onder de naam die we aan het begin hebben bedacht. Nu kan de klant het vinden! Misschien is het je opgevallen dat we de rode draad van het programma aan het einde in slaapstand hebben gezet:

Thread.sleep(Integer.MAX_VALUE);
We hebben alleen de server nodig om lang te draaien. In de IDE lanceren we tegelijkertijd twee main()- methoden: ten eerste de main()-methode van de server (in de ServerMain- klasse, die we al hebben geschreven), en ten tweede de main()-methode van de client (in de ClientMain- klasse, die we hieronder zullen schrijven). Het is belangrijk dat het serverprogramma niet wordt beëindigd terwijl we de client starten, dus we zetten het gewoon voor een lange tijd in de slaapstand. Het zal in ieder geval blijven draaien :) Nu kunnen we de main() methode van onze server gebruiken . Laat het draaien en wacht tot het clientprogramma een methode aanroept :) Laten we nu het clientprogramma gaan schrijven! Het zal getallen naar onze server sturen voor vermenigvuldiging.

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);
   }
}
Het ziet er eenvoudig uit. Maar wat is hier aan de hand? Ten eerste moet de client de unieke naam kennen van het object waarvan het de methoden op afstand zal aanroepen. Dienovereenkomstig hebben we in het clientprogramma de openbare statische eindstring UNIQUE_BINDING_NAME = "server.calculator" gemaakt; variabel. Vervolgens krijgen we in de methode main() toegang tot het register van externe objecten. Om dit te doen, moeten we de methode LocateRegistry.getRegistry() aanroepen en het poortnummer doorgeven dat is gebruikt om ons register te maken in het ServerMain-programma (poort 2732; dit nummer is slechts een voorbeeld — u kunt proberen een ander nummer te gebruiken):

final Registry registry = LocateRegistry.getRegistry(2732);
Nu hoeven we alleen nog maar het gewenste object uit het register te halen! Dit is gemakkelijk, omdat we de unieke naam kennen!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Besteed aandacht aan typecasting. We casten het ontvangen object naar de Calculator- interface, niet naar de RemoteCalculationServer- klasse. Zoals we aan het begin van de les zeiden, vertrouwt RMI op een proxy, dus oproepen op afstand zijn alleen beschikbaar voor de methoden van een interface, niet voor de methoden van klassen. Ten slotte roepen we op afstand de methode multiply() op ons object aan en voeren het resultaat uit naar de console.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
De methode main() van de klasse ServerMain is al geruime tijd actief. Nu is het tijd om de methode main() uit te voeren in het clientprogramma ( ClientMain )! Console-uitvoer:

600
Dat is het! Ons programma (eigenlijk twee programma's!) deed wat het moest doen :) Als je de tijd en het verlangen hebt, kun je dit een beetje opfleuren. Zorg er bijvoorbeeld voor dat de rekenmachine de vier standaard rekenkundige bewerkingen ondersteunt en geef getallen niet door als primitieve typen, maar als CalculationInstance(int x, int y) objecten. Tot de volgende les! :)
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION