John Squirrels
Nivå
San Francisco

Java RMI

Publicerad i gruppen
Hej! Idag ska vi överväga ett ganska intressant ämne: Java RMI. Detta står för Remote Method Invocation. Du kan använda RMI för att tillåta två program att kommunicera med varandra, även om de finns på olika datorer. Låter det coolt? :) Och det är inte så svårt att göra! I dagens lektion kommer vi att analysera delarna av RMI-interaktionen och ta reda på hur man konfigurerar den. Det första vi behöver är en klient och en server. Vi behöver egentligen inte dyka djupt in i datorterminologi. När det kommer till RMI är det bara två program. En av dem kommer att inkludera ett objekt, och den andra kommer att anropa metoder för det objektet. Anropa metoder för ett objekt som finns i ett annat program - nu är det något vi inte har gjort än! Det är dags att prova! :) För att undvika att fastna, låt' s hålla vårt program enkelt. I allmänhet utför en server vissa beräkningar som begärs av en klient. Och så kommer det att vara med oss. Vår server kommer att vara ett enkelt kalkylatorprogram. Det kommer bara att ha en metod:multiplicera() . Den kommer att multiplicera två siffror som skickas till den av klientprogrammet och sedan returnera resultatet. Först och främst behöver vi ett gränssnitt:

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

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Varför behöver vi ett gränssnitt? Eftersom RMI förlitar sig på att skapa proxyservrar, som du studerade i tidigare lektioner . Som du säkert kommer ihåg arbetar vi med proxyservrar genom gränssnitt, inte klasser. Det finns 2 viktiga krav för vårt gränssnitt!
  1. Det måste utöka fjärrgränssnittet.
  2. Alla dess metoder måste ge ett RemoteException (IDE kommer inte att göra detta automatiskt - du måste lägga till detta manuellt!).
Nu måste vi skapa en serverklass som implementerar vårt Calculator- gränssnitt. RMI i praktiken - 2Även här är allt ganska enkelt:

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
Det finns egentligen inget att kommentera här :) Nu måste vi skriva ett serverprogram som ska konfigurera och köra vårt kalkylatorobjekt. Det kommer att se ut så här:

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

   }
}
Låt oss ta reda på det här :) På den första raden deklarerar vi någon strängvariabel:

public static final String UNIQUE_BINDING_NAME = "server.calculator";
Denna sträng är fjärrobjektets unika namn. Vårt klientprogram använder detta namn för att hitta vår server: du kommer att se detta senare. Därefter skapar vi vårt kalkylatorobjekt:

final RemoteCalculationServer server = new RemoteCalculationServer();
Allt är klart här. Vad som kommer härnäst är mer intressant:

final Registry registry = LocateRegistry.createRegistry(2732);
Detta registerobjekt är ett register över fjärrobjekt. Det här är objekt som andra program kan komma åt på distans :) Vi skickade numret 2732 till metoden LocateRegistry.createRegistry() . Detta är portnumret — ett unikt nummer som andra program kommer att använda för att hitta vårt objektregister (igen, du kommer att se detta nedan). Går rakt fram... Låt oss se vad som händer i nästa rad:

Remote stub = UnicastRemoteObject.exportObject(server, 0);
Vi skapar en stubb i denna linje. En stubb kapslar in hela fjärrsamtalet. Du kan betrakta detta som den viktigaste delen av RMI. Vad gör den?
  1. Den tar emot all information om ett fjärranrop av någon metod.
  2. Om metoden har parametrar kommer stubben att deserialisera dem. Var uppmärksam på denna punkt! Argumenten som du skickar till de fjärranropade metoderna måste kunna serialiseras (de kommer trots allt att sändas över nätverket). Detta är inga problem för oss – vi sänder bara nummer. Men om du sänder objekt, glöm inte detta krav!
  3. Efter det anropar stubben den önskade metoden.
Vi skickar vårt kalkylatorserverobjekt till metoden UnicastRemoteObject.exportObject() . Det är så vi gör det möjligt att på distans anropa dess metoder. Det finns bara en sak kvar att göra:

registry.bind(UNIQUE_BINDING_NAME, stub);
Vi "registrerar" vår stubb i fjärrobjektregistret under det namn vi hittade på i början. Nu kommer kunden att kunna hitta den! Du kanske märkte att vi lade programmets huvudtråd i vila i slutet:

Thread.sleep(Integer.MAX_VALUE);
Vi behöver bara servern att köra länge. I IDE kommer vi samtidigt att starta två main()- metoder: för det första serverns main()-metod (i klassen ServerMain , som vi redan har skrivit), och för det andra, klientens main()-metod (i klassen ClientMain , som vi kommer att skriva nedan). Det är viktigt att serverprogrammet inte avslutas medan vi startar klienten, så vi lägger den bara i vila länge. Hur som helst kommer den att fortsätta köras :) Nu kan vi köra vår servers main()- metod. Låt det köra och vänta på att klientprogrammet ska anropa någon metod :) Låt oss nu skriva klientprogrammet! Det kommer att skicka siffror till vår server för multiplikation.

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);
   }
}
Det ser enkelt ut. Men vad händer här? Först måste klienten känna till det unika namnet på objektet vars metoder den kommer att anropa på distans. Följaktligen skapade vi i klientprogrammet den offentliga statiska slutsträngen UNIQUE_BINDING_NAME = "server.calculator"; variabel. Därefter, i main() -metoden, får vi tillgång till registret över fjärrobjekt. För att göra detta måste vi anropa metoden LocateRegistry.getRegistry() och skicka portnumret som används för att skapa vårt register i ServerMain-programmet (port 2732; detta nummer är bara ett exempel - du kan prova att använda ett annat nummer):

final Registry registry = LocateRegistry.getRegistry(2732);
Nu behöver vi bara hämta önskat objekt från registret! Detta är enkelt, eftersom vi känner till dess unika namn!

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Var uppmärksam på typgjutning. Vi castar det mottagna objektet till Calculator- gränssnittet, inte till klassen RemoteCalculationServer . Som vi sa i början av lektionen förlitar sig RMI på en proxy, så fjärranrop är endast tillgängliga för metoderna för ett gränssnitt, inte metoderna för en klass. Slutligen anropar vi multiply() -metoden på vårt objekt på distans och matar ut resultatet till konsolen.

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
ServerMain - klassens main()- metod har redan körts länge. Nu är det dags att köra metoden main() i klientprogrammet ( ClientMain ) ! Konsolutgång:

600
Det är allt! Vårt program (två program, faktiskt!) gjorde vad det skulle :) Har du tid och lust kan du krydda det här lite. Låt till exempel räknaren stödja de fyra vanliga aritmetiska operationerna och skicka siffror inte som primitiva typer, utan som CalculationInstance(int x, int y) -objekt. Vi ses i nästa lektion! :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION