Remote Method Invocation (RMI)
Socket based communications requires that you make explicit connections
between servers and clients and transmit data through those connections.
The Remote Method Invocation (RMI) in Java simplifies this situation by
not requiring you to make explicit connections. Objects located on remote
hosts can through this framework be accessed as if they were situated
locally. The underlying connection and transmission of data are handled
implicitly by the JVM. These are some terms that you must be familiar
with:
- Server: An program that provides services to objects residing on
other machines.
- Service contract: An interface that defines the services provided
by the server.
- Client: An object that uses the services provided by the server
program on a remote machine.
- Registry: A service provided to clients to locate a server on a
remote machine providing the service.
- Stub: An object that resides on the same host as the client and serves
as a proxy or surrogate, of the remote server.
- Skeleton: An object that resides on the same host as the server,
receiving requests from the stubs and dispatching the requests to
the server.
The client and server classes are written by programmers. The stubs and
skeletons are created by the RMI compiler from the server code. This is
how the RMI process works:
- The client invokes a method that is offered by the server. The invocation
is received by the stub.
- The stub arranges the request and data in a linear stream. This is known
as marshalling and sends that information to the machine that the
server resides on.
- The skeleton receives the request and unmarshals the information and
invokes the method on the server object.
- The server executes the method and returns the result to the skeleton.
- The skeleton marshals the result and sends it to the stub.
- The stub unmarshals the result and sends the result to the client
object.
In this simple example on Remote Method Invocation, the server offers the
services of a calculator that can perform elementary arthimetic operations.
These are the steps that you would need to perform to set up the system. The
sample code is appended below.
- Clients must know what services the Calculator Server provides.
RMI: ICalculator interface lists the methods available to remote clients.
- Clients must find a Calculator object on the server.
RMI: The Calculator Server registers an object with a special server,
called the rmiregistry, so that clients can look it up by name.
- Clients must be able to pass arguments to, and invoke a method of the
Calculator object located on the server.
RMI: A special compiler called rmic creates a stub class for use on the
client, and a skeleton class for use on the server. The stub takes the
request from the client, passes the arguments to the skeleton which
invokes the Calculator methods, and send the return value back to the
stub which passes it to the client.
To set up the RMI example do the following:
On the server machine:
- Compile ICalculator.java, Calculator.java, and CalculatorServer.java
- Create the stub and skeleton classes using the command rmic
Calculator
- Copy the Calculator_Stub.class to the client site
- Start the registry using the command rmiregistry&
- Start CalculatorServer using java CalculatorServer serverHostname &
On the client machine:
- Compile ICalculator.java and CalculatorClient.java
- Run CalculatorClient using the command java CalculatorClient
serverHostname
/*
Interface for the Calculator class
*/
import java.rmi.*;
public interface ICalculator extends java.rmi.Remote
{
public long add (long a, long b) throws java.rmi.RemoteException;
public long sub (long a, long b) throws java.rmi.RemoteException;
public long mul (long a, long b) throws java.rmi.RemoteException;
public long div (long a, long b) throws java.rmi.RemoteException;
}
/*
Implementation of the ICalculator interface. This class offers
the service that clients can invoke.
*/
import java.rmi.*;
public class Calculator extends java.rmi.server.UnicastRemoteObject
implements ICalculator
{
public Calculator() throws java.rmi.RemoteException
{
super();
}
public long add (long a, long b) throws java.rmi.RemoteException
{
return a + b;
}
public long sub (long a, long b) throws java.rmi.RemoteException
{
return a - b;
}
public long mul (long a, long b) throws java.rmi.RemoteException
{
return a * b;
}
public long div (long a, long b) throws java.rmi.RemoteException
{
return a / b;
}
}
/*
This class starts the server that offers the CalculatorService
to clients.
*/
import java.rmi.*;
public class CalculatorServer
{
public CalculatorServer(String s)
{
try
{
ICalculator c = new Calculator();
String url = "rmi://" + s + ":1099/CalculatorService";
Naming.rebind (url, c);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main (String[] args)
{
new CalculatorServer (args[0]);
}
}
/*
This is a client of the Calculator Service offered by the
Calculator class at a remote site.
*/
import java.rmi.*;
public class CalculatorClient
{
public static void main (String[] args)
{
try
{
String url = "rmi://" + args[0] + ":1099/CalculatorService";
ICalculator c = (ICalculator) Naming.lookup (url);
System.out.println (c.add(3, 5));
System.out.println (c.sub(9, 5));
System.out.println (c.mul(3, 5));
System.out.println (c.div(15, 5));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}