RMI (Remote Method Invocation)

    It so happened that the task posed required the use of a remote method call. Having rummaged on Habré, I did not find anything on this issue (I wanted to read something as a first acquaintance, before reading the documentation). Having studied the specifications on java.sun.com I hasten to share with you my first article. :)

    "What is RMI?"


    Remote method Invocation - a mechanism that allows you to call the method of a remote object. According to him, all operations for preparing and transmitting data are encapsulated in the called method of the client stub object (stub). The method call itself is no different from the method call of a regular local object, with a few exceptions:
    • all parameters are passed by value (i.e. copies of objects, not links to them, as it usually happens) - fixed below. Thanks KonstantinSolomatov
    • local objects are passed by value (copies)
    • when transmitting a remote object, if it is exported, the stub of this object is transmitted
    • transferred objects must be serializable
    • except for all other exceptional situations, when calling a remote method, a RemoteException may be thrown (marshalization / unmarshalization errors, data transfer and other possible protocol errors)
    It should also be noted that when calling a method, we are working with a remote interface, and not with a remote class.

    "Why is this needed?"


    The task of RMI is the organization of client-server interaction. This means that you don’t have to worry about data transfer and preprocessing (protocol, etc.). Conveniently? Yes. But not in all cases. If your client-server environment implies the work of programs written not only in java, RMI is of little use (although with a great desire, you can try to "get out" using JNI).

    “Let's write something!”


    Let's. Consider the example of distributed computing. Our task is this: we will search for prime numbers in the simplest way, by enumeration. In a distributed manner, we will check the numbers by selecting the divisors from 2 to sqrt (n), where n is the number we are checking. (“Distributed computing” is a big name for such an example. But we calculate it? Yes! Distributed? Distributed!)

    We will solve the problem this way: there is a server that will “feed” the numbers to check for “registered” clients, therefore we will interact in both directions (client-> server - registration, server-> client - number for verification), for this we will describe 2 interfaces:
    1. public interface ClientRegister extends Remote {
    2.   public void register (PrimeChecker checker) throws RemoteException;
    3. }
    4.  
    5. public interface PrimeChecker extends Remote {
    6.   public boolean check (BigDecimal number) throws RemoteException;
    7. }
    * This source code was highlighted with Source Code Highlighter.

    The ClientRegister interface is used by the client to register itself on the server as PrimeChecker`a. The server uses PrimeChecker to send the client a number for verification.

    As you have already noticed, the remote interface must extend, directly or indirectly, the Remote interface. Among other exceptions, we define a RemoteException (we talked about it above).

    Let's start server implementation ( full code ):
    1. public class PrimeNumbersSearchServer implements ClientRegister {
    2.  
    3.   ...
    4.  
    5.   public static void main(String[] args) {
    6.     PrimeNumbersSearchServer server = new PrimeNumbersSearchServer();
    7.  
    8.     try {
    9.       ClientRegister stub = (ClientRegister)UnicastRemoteObject.exportObject(server, 0);
    10.  
    11.       Registry registry = LocateRegistry.createRegistry(12345);
    12.       registry.bind("ClientRegister", stub);
    13.  
    14.       server.startSearch();
    15.     } catch (Exception e) {
    16.       System.out.println ("Error occured: " + e.getMessage());
    17.       System.exit (1);
    18.     }
    19.   }
    20. }
    * This source code was highlighted with Source Code Highlighter.

    Let's analyze the initialization:
    1. ClientRegister stub = (ClientRegister)UnicastRemoteObject.exportObject(server, 0);
    * This source code was highlighted with Source Code Highlighter.

    We export the remote object and get a stub, through which the client will call the methods of our object. The second parameter, exportObject, is the port that will be used to connect to the remote object, 0 is the choice of any free port. stub must be passed to the client. Here completely different options are possible. You can even pass stub to the client on a 3.5 '' floppy disk :) We will use an RMI recorder. It can be created either inside our vm, or you can use the “external” one represented by the rmiregistry utility. I used the first option:
    1. Registry registry = LocateRegistry.createRegistry(12345);
    2. registry.bind("ClientRegister", stub);
    * This source code was highlighted with Source Code Highlighter.

    Create a registrar and bind our stub with the name ClientRegister. The registrar will accept connections at port 12345.

    Now the client ( full code ):
    1. public class PrimeNumbersSearchClient implements PrimeChecker {
    2.  
    3.   ...
    4.  
    5.   public static void main(String[] args) {
    6.     PrimeNumbersSearchClient client = new PrimeNumbersSearchClient();
    7.  
    8.     try {
    9.       Registry registry = LocateRegistry.getRegistry(null, 12345);
    10.       ClientRegister server = (ClientRegister)registry.lookup("ClientRegister");
    11.  
    12.       PrimeChecker stub = (PrimeChecker)UnicastRemoteObject.exportObject(client, 0);
    13.       server.register(stub);
    14.  
    15.     } catch (Exception e) {
    16.       System.out.println ("Error occured: " + e.getMessage());
    17.       System.exit (1);
    18.     }
    19.   }
    20. }
    * This source code was highlighted with Source Code Highlighter.

    The client needs to get a server stub in order to register.
    1. Registry registry = LocateRegistry.getRegistry(null, 12345);
    2. ClientRegister server = (ClientRegister)registry.lookup("ClientRegister");
    * This source code was highlighted with Source Code Highlighter.

    We find the remote registrar and request a stub associated with it with the name “ClientRegister”. The first parameter is LocateRegistry.getRegistry (null, 12345) is the host (null is localhost), the second is the port.

    Next, we export the client remote object and pass it to the stub server (already client) - register. The server will add the client to the queue of available checkers and begin to send him numbers for verification. After checking, if it completed without errors, the client again enters the queue, etc.

    UPD: ported to Java

    Also popular now: