Introduction
Remote Procedure Call (RPC) and Remote Method Invocation (RMI) are two fundamental communication mechanisms in distributed systems. They allow a program to execute procedures or methods on a remote server as if they were local calls. This section will cover the basic concepts, differences, and practical examples of RPC and RMI.
Key Concepts
Remote Procedure Call (RPC)
- Definition: RPC is a protocol that one program can use to request a service from a program located on another computer in a network.
- Mechanism:
- Client: Initiates the request.
- Server: Executes the requested procedure and returns the result.
- Stub: Client-side proxy that represents the remote procedure.
- Skeleton: Server-side proxy that handles the actual execution of the procedure.
- Communication: Typically uses a request-response model over TCP/IP.
Remote Method Invocation (RMI)
- Definition: RMI is a Java-specific implementation of RPC that allows invoking methods on remote objects.
- Mechanism:
- Client: Invokes methods on remote objects.
- Server: Hosts the remote objects.
- Stub: Client-side proxy that represents the remote object.
- Skeleton: Server-side proxy that handles the actual method invocation (in newer versions, the skeleton is not required).
- Communication: Uses Java's native serialization mechanism over TCP/IP.
Differences Between RPC and RMI
Feature | RPC | RMI |
---|---|---|
Language Support | Language-agnostic | Java-specific |
Object-Oriented | No | Yes |
Serialization | Custom serialization | Java's native serialization |
Complexity | Simpler, procedural | More complex, object-oriented |
Use Case | General-purpose, cross-language calls | Java applications needing remote object access |
Practical Examples
Example of RPC
Server Code (Python)
# rpc_server.py import xmlrpc.server def add(x, y): return x + y server = xmlrpc.server.SimpleXMLRPCServer(("localhost", 8000)) print("Listening on port 8000...") server.register_function(add, "add") server.serve_forever()
Client Code (Python)
# rpc_client.py import xmlrpc.client proxy = xmlrpc.client.ServerProxy("http://localhost:8000/") result = proxy.add(5, 3) print(f"Result of add(5, 3): {result}")
Example of RMI
Server Code (Java)
// RMIServer.java import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class RMIServer extends UnicastRemoteObject implements Adder { public RMIServer() throws RemoteException { super(); } public int add(int x, int y) { return x + y; } public static void main(String[] args) { try { RMIServer server = new RMIServer(); Naming.rebind("rmi://localhost:5000/adder", server); System.out.println("Server is ready."); } catch (Exception e) { System.out.println(e); } } }
Client Code (Java)
// RMIClient.java import java.rmi.Naming; public class RMIClient { public static void main(String[] args) { try { Adder stub = (Adder) Naming.lookup("rmi://localhost:5000/adder"); System.out.println("Result of add(5, 3): " + stub.add(5, 3)); } catch (Exception e) { System.out.println(e); } } }
Interface Code (Java)
// Adder.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Adder extends Remote { int add(int x, int y) throws RemoteException; }
Practical Exercises
Exercise 1: Implement a Simple RPC Service
- Create an RPC server that provides a multiplication service.
- Write a client that uses this service to multiply two numbers.
Solution
Server Code (Python)
# rpc_server.py import xmlrpc.server def multiply(x, y): return x * y server = xmlrpc.server.SimpleXMLRPCServer(("localhost", 8000)) print("Listening on port 8000...") server.register_function(multiply, "multiply") server.serve_forever()
Client Code (Python)
# rpc_client.py import xmlrpc.client proxy = xmlrpc.client.ServerProxy("http://localhost:8000/") result = proxy.multiply(5, 3) print(f"Result of multiply(5, 3): {result}")
Exercise 2: Implement a Simple RMI Service
- Create an RMI server that provides a subtraction service.
- Write a client that uses this service to subtract two numbers.
Solution
Server Code (Java)
// RMIServer.java import java.rmi.Naming; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public class RMIServer extends UnicastRemoteObject implements Subtractor { public RMIServer() throws RemoteException { super(); } public int subtract(int x, int y) { return x - y; } public static void main(String[] args) { try { RMIServer server = new RMIServer(); Naming.rebind("rmi://localhost:5000/subtractor", server); System.out.println("Server is ready."); } catch (Exception e) { System.out.println(e); } } }
Client Code (Java)
// RMIClient.java import java.rmi.Naming; public class RMIClient { public static void main(String[] args) { try { Subtractor stub = (Subtractor) Naming.lookup("rmi://localhost:5000/subtractor"); System.out.println("Result of subtract(5, 3): " + stub.subtract(5, 3)); } catch (Exception e) { System.out.println(e); } } }
Interface Code (Java)
// Subtractor.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Subtractor extends Remote { int subtract(int x, int y) throws RemoteException; }
Common Mistakes and Tips
- RPC: Ensure that the server and client are using the same protocol and data serialization format.
- RMI: Make sure the RMI registry is running and the correct URL is used for binding and lookup.
- General: Handle network exceptions and ensure proper error handling in both client and server code.
Conclusion
In this section, we explored the concepts of RPC and RMI, their differences, and practical examples. RPC is a language-agnostic protocol suitable for general-purpose remote procedure calls, while RMI is Java-specific and supports remote method invocation on objects. Understanding these mechanisms is crucial for designing and implementing distributed systems that require remote communication.
Distributed Architectures Course
Module 1: Introduction to Distributed Systems
- Basic Concepts of Distributed Systems
- Models of Distributed Systems
- Advantages and Challenges of Distributed Systems