We have seen that shared memory and message passing are the basic forms of inter-process communication (IPC). We can build on top of these to create more abstract, hence easier to use forms of IPC such as Remote Procedure Call (RPC) and its object-oriented successor, Remote Method Invocation (RMI).
RPC was the heart of Sun's Open Network Computing Architecture (ONCA). RPC was also at the heart of the Open Group's Distributed Computing Environment (DCE).
As its name implies, remote procedure call (RPC) enables program C to call a procedure or function declared in program S. Thus, we can view program C as a client and program S as a server that offers services in the form of procedures.
RPC is not unlike a library of procedures that program C shares with other client programs, except in that case the library must be linked into the address space of each client.
Of course RPC is only an illusion. It is really built upon the message passing services of some network's transport layer. A library of virtual procedures called a proxy is linked into the client's address space. The proxy hides the nasty details of network communication from the clients:
More specifically, when a client calls a proxy, the proxy translates the call into a message (this is called parameter marshaling), which it sends to the server. On the server side another proxy receives the message, translates it into a procedure call (this is called parameter de-marshaling), calls the appropriate procedure, marshals the result, then sends the result back to the client:
Remote Method Invocation (RMI) is just the object-oriented version of RPC. In this case the procedures are the methods of a remote object. Here's how it works: a server decides to export some of its objects. This means that the server registers the names (a URI for example) and locations of these objects with some naming server. (A naming server is like the white pages in a phone book. It's a giant table that stores associations between names and addresses.)
Subsequently, a client queries the naming server using the name of the remote object. This means the client doesn't need to know the actual location of the object. The query produces a proxy object called a stub in the client's address space. The proxy object implements the same interface as the remote object, hence is indistinguishable from the remote object from the client's perspective. The stub marshals parameters and interfaces with the transport layer of the network.
Proxies called skeletons are used on the server side. Skeletons, like stubs, also implement the same interface as the remote object, and hence are indistinguishable from it. The skeleton interfaces with the transport layer of the network on the server side. It de-marshals parameters and delegates to the remote object.
Here's a typical scenario:
With RMI we can develop distributed object-oriented applications (a.k.a. Distributed Object Architectures). In such applications participants (clients, servers, peers, filters, etc.) are objects that communicate using method invocation syntax and semantics as if they all resided in the same program. Distributed object-oriented applications are easier to develop than traditional distributed applications because:
1. Details of socket-based communication are hidden.
2. Marshaling and de-marshaling of data (i.e., translating objects to and from strings) is hidden.
3. Communication is service-oriented rather than data-oriented.
4. Delivers the benefits of object-oriented design (encapsulation, inheritance, polymorphism, etc.) to distributed architectures.
ODP is an ISO model for distributed object architectures. In this model remote objects are called components. In addition to the features described above, ODP adds:
1. Components can be heterogeneous-- they can be implemented in different languages.
2. Openness-- communication protocols are public rather than proprietary. This allows inter-operability between applications developed by different (possibly competing) vendors. This adds to the functionality hence the appeal of these applications.
3. In addition to naming registries, clients can discover components using service registries. (This feature is called discovery.) If a naming registry is analogous to the white pages of a phone book, then a service registry is analogous to the yellow pages. Components register the interfaces they implement with a service registry. A client in search of a particular interface can query the service registry to obtain a list of the names of all components that implement that interface. (See http://www.joaquin.net/ODP/).
There are several notable implementations of the ODP architecture. The best known is the Object Management Group's (http://www.omg.org/) Object Management Architecture or OMA. The OMA reference architecture envisions layers of applications, services, and facilities, all written in different Object-Oriented languages. Remote method invocation is provided by an object request broker or ORB. (In fact OMA better known as CORBA-- Common Object Request Broker Architecture).
Microsoft's COM (Component Object Model) architecture implemented ODP for programs running on the same Windows platform. This enabled the popular Object Linking and Embedding (OLE) technology. The DCOM extension allowed OLE to reach across networks.
The Artificial Intelligence (AI) community has been experimenting with distributed architectures for some time. These architectures are modeled after simple societies in which members (called agents) follow simple, possibly different, rules of behavior that contribute (often in unpredictable ways) to the overall behavior of the society. The behavior of the society is called an emergent behavior because it is not explicitly programmed.
It was only a matter of time before distributed AI architectures merged with distributed object-oriented architectures to produce distributed agent architectures. The FIPA Distributed Agent Architecture (http://www.fipa.org/) is a standard model for such architectures, analogous to and built on top of ODP. For a more complete discussion, see:
http://www.mathcs.sjsu.edu/faculty/pearce/cs251a/abs.htm
The World Wide Web (WWW) is rapidly moving from a document-oriented system to a service-oriented system in which web-based applications are constructed from web-based services that communicate using XML messages. The details can be found at:
http://www.w3.org/2002/ws/arch/
Although not FIPA compliant, WSA is a distributed agent system.
Java RMI is meant to support distributed object-oriented applications written in Java. Theoretically, it is possible to modify Java RMI to support heterogeneous objects and discovery (the features required by ODP), but basic Java RMI does not go this far.
import java.rmi.*;
public interface ICalculator extends Remote {
public Double add(Double arg1, Double
arg2)
throws RemoteException;
public Double mul(Double arg1, Double
arg2)
throws RemoteException;
}
import java.rmi.*;
import java.rmi.server.*;
public class Calculator
extends UnicastRemoteObject
implements ICalculator {
public Calculator() throws
RemoteException { }
public Double add(Double arg1, Double
arg2)
throws RemoteException {
return new Double(arg1.doubleValue()
+ arg2.doubleValue());
}
public Double mul(Double arg1, Double
arg2)
throws RemoteException {
return new Double(arg1.doubleValue()
* arg2.doubleValue());
}
}
import java.rmi.*;
import java.rmi.registry.*;
public class CalcServer {
public static void main(String[] args)
{
try {
Calculator calc = new
Calculator(); // exported object
String uri =
"rmi://localhost:1099/calculator";
Naming.rebind(uri, calc);
// re-reg exported object
}
catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
import java.io.*;
import java.rmi.*;
public class CalcClient {
public static void main(String[] args)
{
try {
String uri = "rmi://localhost:1099/calculator";
ICalculator calc =
(ICalculator)Naming.lookup(uri);
Double arg1 = new Double(6);
Double arg2 = new Double(7);
Double result = calc.add(arg1,
arg2);
System.out.println("result =
" + result);
result = calc.mul(arg1, arg2);
System.out.println("result =
" + result);
} catch(Exception e) {
System.err.println(e.getMessage());
}
}
}
After compiling Calculator.java, generate stubs and skeletons from a console prompt using the RMI compiler tool:
console> rmic Calculator
You should now see the files:
Calculator_Stub.class
Calculator_Skel.class
The Java name server can be started from a console prompt using the command:
console> rmiregistry 1099
The default port is 1099, so specifying this port is not necessary.
In a separate console window, start the server:
console> java CalcServer
In a third console window, start the client:
console> java CalcClient
Warning: the RMI naming registry uses the classpath and/or codebase settings to find the necessary stubs and skeletons.
M.L. Liu; Distributed Computing: Principles and Applications; Addison-Wesley; 2004.
William Grosso; Java RMI; O'Reilly; 2001.
Kris Magnusson, David Flanagan, Jim Farley, William Crawford; Java in a Nutshell, Fourth Edition; O'Reilly; 2001.