Introducció

En aquest tema, explorarem dos mecanismes fonamentals per a la comunicació en sistemes distribuïts: Remote Procedure Call (RPC) i Remote Method Invocation (RMI). Aquests mecanismes permeten que els programes executats en diferents màquines puguin comunicar-se i col·laborar de manera eficient.

Objectius

  • Entendre els conceptes bàsics de RPC i RMI.
  • Aprendre com funcionen i com es poden implementar.
  • Comparar RPC i RMI per identificar les seves diferències i similituds.
  • Proporcionar exemples pràctics i exercicis per reforçar els conceptes apresos.

Conceptes Bàsics

Remote Procedure Call (RPC)

RPC és un protocol que permet a un programa executar una subrutina (procediment) en una altra adreça espacial (normalment en una màquina remota) com si fos una crida local.

Característiques de RPC

  • Transparència: L'objectiu de RPC és fer que la crida a un procediment remot sembli una crida local.
  • Interfície: Utilitza una interfície definida per a especificar les funcions que es poden cridar remotament.
  • Serialització: Les dades es serialitzen (marshalling) per enviar-les a través de la xarxa i es deserialitzen (unmarshalling) en el costat receptor.

Remote Method Invocation (RMI)

RMI és un mecanisme similar a RPC, però específic per a Java, que permet a un objecte invocar mètodes en un altre objecte situat en una màquina remota.

Característiques de RMI

  • Orientat a Objectes: A diferència de RPC, RMI treballa amb objectes i permet cridar mètodes en objectes remots.
  • Serialització d'Objectes: RMI utilitza la serialització d'objectes Java per enviar dades a través de la xarxa.
  • Registre de Serveis: RMI proporciona un registre de serveis (RMI registry) on els objectes remots es poden registrar i localitzar.

Funcionament de RPC

Passos per a una Crida RPC

  1. Definició de la Interfície: Es defineix una interfície que especifica els procediments que es poden cridar remotament.
  2. Implementació del Servei: Es crea una implementació del servei que defineix el comportament dels procediments remots.
  3. Stub i Skeleton:
    • Stub: Actua com a representant del client i s'encarrega de la serialització de les dades.
    • Skeleton: Actua com a representant del servidor i s'encarrega de deserialitzar les dades i cridar el procediment adequat.
  4. Comunicació: El stub envia la crida al skeleton a través de la xarxa, i el skeleton retorna el resultat al stub.

Exemple de RPC en 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()
# rpc_client.py
import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
result = proxy.add(5, 3)
print("Result:", result)

Funcionament de RMI

Passos per a una Crida RMI

  1. Definició de la Interfície: Es defineix una interfície que especifica els mètodes que es poden cridar remotament.
  2. Implementació del Servei: Es crea una implementació del servei que defineix el comportament dels mètodes remots.
  3. Registre de Serveis: El servei es registra en el RMI registry perquè els clients el puguin localitzar.
  4. Comunicació: El client utilitza el RMI registry per obtenir una referència a l'objecte remot i cridar els seus mètodes.

Exemple de RMI en Java

// RMIInterface.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RMIInterface extends Remote {
    int add(int x, int y) throws RemoteException;
}
// RMIServer.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class RMIServer implements RMIInterface {
    public int add(int x, int y) {
        return x + y;
    }

    public static void main(String[] args) {
        try {
            RMIServer obj = new RMIServer();
            RMIInterface stub = (RMIInterface) UnicastRemoteObject.exportObject(obj, 0);
            Registry registry = LocateRegistry.createRegistry(1099);
            registry.bind("RMIInterface", stub);
            System.out.println("Server ready");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// RMIClient.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIClient {
    public static void main(String[] args) {
        try {
            Registry registry = LocateRegistry.getRegistry("localhost");
            RMIInterface stub = (RMIInterface) registry.lookup("RMIInterface");
            int result = stub.add(5, 3);
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Comparació entre RPC i RMI

Característica RPC RMI
Paradigma Procedural Orientat a Objectes
Llenguatge Multi-llenguatge Java
Serialització Dades primitives Objectes Java
Registre de Serveis No Sí (RMI registry)
Facilitat d'ús Simple Més complex

Exercicis Pràctics

Exercici 1: Implementar un Servei RPC

  1. Defineix una interfície per a un servei que tingui un procediment multiply que multipliqui dos nombres.
  2. Implementa el servei en un servidor RPC.
  3. Escriu un client que cridi el procediment multiply i mostri el resultat.

Exercici 2: Implementar un Servei RMI

  1. Defineix una interfície per a un servei que tingui un mètode concatenate que concateni dues cadenes de text.
  2. Implementa el servei en un servidor RMI.
  3. Escriu un client que cridi el mètode concatenate i mostri el resultat.

Solucions

Solució Exercici 1

# 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()
# rpc_client.py
import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
result = proxy.multiply(5, 3)
print("Result:", result)

Solució Exercici 2

// RMIInterface.java
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RMIInterface extends Remote {
    String concatenate(String a, String b) throws RemoteException;
}
// RMIServer.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class RMIServer implements RMIInterface {
    public String concatenate(String a, String b) {
        return a + b;
    }

    public static void main(String[] args) {
        try {
            RMIServer obj = new RMIServer();
            RMIInterface stub = (RMIInterface) UnicastRemoteObject.exportObject(obj, 0);
            Registry registry = LocateRegistry.createRegistry(1099);
            registry.bind("RMIInterface", stub);
            System.out.println("Server ready");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// RMIClient.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RMIClient {
    public static void main(String[] args) {
        try {
            Registry registry = LocateRegistry.getRegistry("localhost");
            RMIInterface stub = (RMIInterface) registry.lookup("RMIInterface");
            String result = stub.concatenate("Hello, ", "World!");
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Resum

En aquest tema, hem après sobre RPC i RMI, dos mecanismes essencials per a la comunicació en sistemes distribuïts. Hem explorat les seves característiques, el seu funcionament i hem vist exemples pràctics de com implementar-los. També hem comparat RPC i RMI per entendre millor les seves diferències i similituds. Finalment, hem proporcionat exercicis pràctics per reforçar els conceptes apresos.

© Copyright 2024. Tots els drets reservats