JavaRush /Java Blog /Random EN /RMI: practice of use

RMI: practice of use

Published in the Random EN group
Hello! Today we will look at a rather interesting topic - RMI . This stands for Remote Method Invocation . RMI: practice of use - 1With RMI, you can teach two programs to communicate with each other, even if they are on different computers. Sounds cool? :) But it’s not so difficult to do! In today's lecture we will understand what parts RMI interaction consists of and how to configure it. The first thing we need is a client and a server . You don’t have to go too deep into computer terminology. In the case of RMI, these are simply two programs. One of them will contain some object, and the second will call methods of this object. Calling methods of an object in one program that is located in another program - we have never done this before! It's time to try it! :) In order not to drown in the wilds, let our program be simple. In general, servers usually carry out some kind of calculations that the client requests. It will be the same for us. We will have a simple calculator program as a server. She will have only one method - multiply(). It will multiply the two numbers sent to it by the client program and return the result. First of all we need an interface:
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
Why do we need an interface? The fact is that the work of RMI is based on creating proxies, which you studied in one of the previous lectures . And work with proxies, as you probably remember, is carried out precisely at the level of interfaces, not classes. There are 2 important requirements for our interface!
  1. It must inherit the Remote token interface.
  2. All its methods must throw a RemoteException (this is not done automatically in the IDE, you have to write it manually!).
Now we need to create a server class that will implement our interface Calculator. RMI: practice of use - 2Everything here is also quite simple:
import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

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

}
There’s not even much to comment on here :) Now we need to write a server program that will configure and launch our server calculator class. It will look like this:
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);

   }
}
Let's figure it out :) In the first line we create some kind of string variable:
public static final String UNIQUE_BINDING_NAME = "server.calculator";
This string is the unique name of the remote object . By this name the client program will be able to find our server: you will see this later. Next we create our calculator object:
final RemoteCalculationServer server = new RemoteCalculationServer();
Everything is clear here. The following is more interesting:
final Registry registry = LocateRegistry.createRegistry(2732);
This thing called Registry is a registry of deleted objects . “Deleted” not in the sense that we deleted them from the computer, but in the fact that objects from this register can be accessed remotely from other programs :) LocateRegistry.createRegistry()We passed the number 2732 to the method. This is the port number. If you don’t know what a port is, you can read it here , but for now you just need to remember that this is a unique number by which other programs can find our object registry (you will also see this below). Let's move on. Let's see what happens in the next line:
Remote stub = UnicastRemoteObject.exportObject(server, 0);
On this line we create a stub . A stub encapsulates the entire remote call process within itself. It can be said that this is the most important element of RMI. What is she doing?
  1. Receives all information about a remote call to a method.
  2. If the method has parameters, the stub deserializes them. Pay attention to this point! The parameters that you pass to methods for remote calls must be serializable (after all, they will be transmitted over the network). We don’t have such a problem - we just transmit numbers. But if you transfer objects, don't forget about it!
  3. After that, it calls the desired method.
We pass UnicastRemoteObject.exportObject()our server calculator object to the method. This way we make it possible to call its methods remotely. We only have one thing left to do:
registry.bind(UNIQUE_BINDING_NAME, stub);
We “register” our stub in the remote object registry under the name we came up with at the very beginning. Now the client can find it! You may have noticed that at the end we put the main thread of the program to sleep:
Thread.sleep(Integer.MAX_VALUE);
We just need to keep the server running for a long time. We will run two methods in IDEa at once main(): first the server one (in the class ServerMainwe have already written), and then the client one (in the class ClientMainwe will write below). It is important that the server program does not go down while we are launching the client, so we simply put it to sleep for a long time. It will still work :) Now we can run main()our server method. Let it run and wait for the client program to call some method :) Now let's write a client program! It will send numbers to our server to multiply.
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);
   }
}
She looks uncomplicated. What's going on here? First, the client must be aware of the unique name of the object whose methods it will call remotely. Therefore, in the client program we also created a variable. public static final String UNIQUE_BINDING_NAME = "server.calculator"; Next, in the method main()we get access to the register of remote objects. To do this, we need to call the method LocateRegistry.getRegistry()and pass there the port number on which our register was created in the ServerMain program - port 2732 (this number was chosen for the example, you can try using another one):
final Registry registry = LocateRegistry.getRegistry(2732);
Now all we have to do is get the desired object from the register! It's easy because we know his unique name!
Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
Pay attention to type casting. We cast the resulting object to an interface Calculatorrather than a concrete class RemoteCalculationServer . As we said at the beginning of the lecture, RMI is based on the use of a proxy, so a remote call is available only for methods of interfaces, not classes. At the end, we remotely call a method multiply()on our object and print the result to the console.
int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
We launched the method main()in the class ServerMaina long time ago, it’s time to launch the method main()in the client program ClientMain! Console output: 600 That's it! Our program (even two!) successfully fulfilled its function :) If you have time and desire, you can diversify it a little. For example, make sure that the calculator supports all four standard operations, and not numbers, but an object are passed as parameters CalculationInstance(int x, int y). As additional material, you can look at articles and examples - here: See you in the next classes! :)
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION