Está en la página 1de 4

Sistemas Distribuidos

Practica 1: RPC (Remote Procedure Call) Llamado a Procedimientos Remotos.

Objetivos

• Comprenda la comunicación de procesos a nivel de los RPC.


• Implementar comunicación entre procesos mediante RPC.

Introducción

En los sistemas distribuidos los procesos se encuentran en diferentes máquinas o computadoras,


requiriendo para su coordinación de algún mecanismo de comunicación. Uno de estos mecanismos, el
cual es muy flexible y eficiente, son los llamados sockets; sin embargo, el empleo de estos requiere de
un mayor esfuerzo por parte del programador ya que deberá resolver varios problemas para
implementar la comunicación. Existen otras alternativas que le permiten al programador realizar la
comunicación de manera más sencilla, una de estas opciones son los RPC (Remote Procedure Call).

Los RPC proporcionan una interfaz de comunicación cuya operación es semejante al llamado de un
procedimiento, con la diferencia de que, el procedimiento no se ejecuta localmente. Note que los RPC
manejan la conexión y traducción de los datos, algo que con los sockets el programador tendría que
resolver.

Una forma de emplear RPC en Linux es usando la herramienta rpcgen, el cual definir la interfaz
(procedimiento) y los datos que serán transmitidos, de hecho, rpcgen generará todos los archivos
fuente necesarios a partir de la definición de la interfaz, lo único que se tendrá que hacer, es colocar
el código correspondiente.

Ejemplo

Consideremos un programa que se encarga de sumar un par de números complejos1, y de multiplicar


un número complejo por un escalar (real), dicho programa podría ser como se muestra a continuación:

/*Dado que un número complejo tiene la forma de x =a + ib, para realizar operaciones sobre ellos,
debemos crear un nuevo tipo que lo soporte, ya que los que existen (int, long, char, float,
double, etc.) no lo permiten. Por lo anterior, emplearemos una estructura.*/

#include <stdio.h>
#include <stdlib.h>

typedef struct COMPLEX complex; /*Tipo complex*/


struct COMPLEX
{
double fReal; /*Parte real*/
double fImg; /*Parte imaginaria*/
};

complex scSuma (complex a, complex b);


complex scProductoConEscalar (complex a, double c);

int main ()
{
complex x, y, z; /*Unos números complejos*/
double N;
x.fReal = 10; x.fImg = 20;

1
Un número complejo x tiene la siguiente apariencia: x = a + i b. En donde a y b son número reales, e i es el símbolo para
representar a √-1. Por tanto, se dice que a es la parte real del número x y que b es su parte imaginaria.
y.fReal = 30; y.fImg = 40;
N = 0.1;
printf ("N = %f\nx = (%f) + (%f)i\ny = (%f) + (%f)i\n\n", N, x.fReal, x.fImg, y.fReal, y.fImg);
z = scSuma (x, y);
printf ("z = x + y = (%f) + (%f)i\n", z.fReal, z.fImg);
z = scProductoConEscalar (x, N);
printf ("z = x * N = (%f) + (%f)i\n", z.fReal, z.fImg);
return (0);
}

complex scSuma (complex a, complex b)


{ /*La suma se realiza componente a componente,
es decir, real con real e imaginario con imaginario*/
complex scR;
scR.fReal = a.fReal + b.fReal;
scR.fImg = a.fImg + b.fImg;
return (scR);
}

complex scProductoConEscalar (complex a, double c)


{ /*Todo el número complejo se multiplica por c*/
complex scR;
scR.fReal = a.fReal * c;
scR.fImg = a.fImg * c;
return (scR);
}

Código 1. Programa con procedimientos para números complejos.

Note que el programa hace dos llamados a los procedimientos/funciones scSuma y


scProductoConEscalar, y que dichos procedimientos se ejecutan de forma local en la computadora que
ejecuta ese código.

Ahora, consideremos el siguiente escenario, en el cual tenemos dos computadoras:

• CA con una con una poderosa tarjeta gráfica y,


• CB con un procesador de alto desempeño.

Lo ideal sería tener ambas características en un mismo equipo, pero a veces esto no es posible.
Imaginemos que el programa antes citado (Código 1), realiza complejas operaciones (los
procedimientos de suma y producto por escalar), para después mostrar los resultados empleando
características gráficas especiales (los printf). Ejecutando dicho programa en la máquina CA
obtendríamos buenas gráficas, pero posiblemente en un tiempo muy largo; en cambio, en la máquina
CB, obtendríamos resultados muy rápido pero gráficas muy pobres.

Una solución al problema anterior es hacer que los cálculos pesados se realicen en CB, y que los
resultados se muestren en CA; en otras palabras, ejecutando el programa en CA, pero permitiendo que
los procedimientos se ejecuten remotamente en CB. Esto sería uno de los objetivos de los RPC.

Para continuar, es necesario crear un archivo de definición, el cual llevará extensión x. El formato es el
siguiente:

program NOMBRE_PROGRAMA
{
version NOMBRE_VERSION
{
DECLARACION_FUNCION = CONSECUTIVO;
} = NUMERO
} = NUMERO_PROGRAMA
En donde CONSECUTIVO es un número, empezando por el 1, para enumerar las
funciones/procedimientos. NUMERO_PROGRAMA es identificador para el programa remoto (el que
aloja los procedimientos remotos), se especifica en hexadecimal, empezando por 0x20000000. Es
importante mencionar que, por buena costumbre, NOMBRE_PROGRAMA y NOMBRE_VERSION se
escriban en mayúsculas; estos son los identificadores del programa remoto y el nombre asignado a la
versión. Si las funciones requieren estructuras, será necesario declararlas antes.

En nuestro ejemplo, el archivo de definición complex_RPC.x queda como sigue:

typedef struct COMPLEX complex; /*Tipo complex*/


struct COMPLEX
{
double fReal; /*Parte real*/
double fImg; /*Parte imaginaria*/
};

program COMPLEX_OPERACIONES
{
version COMPLEX_OPER_1
{
complex scSuma (complex a, complex b) = 1;
complex scProductoConEscalar (complex a, double c) = 2;
} = 1;
} = 0x20000001;

Código 2. Definición del proyecto RPC.

El siguiente caso será crear los archivos fuente a partir del archivo de definición anterior, para ello
ejecutamos el siguiente comando:

$ rpcgen -a -N complex_RPC.x

Lo anterior creará los siguientes archivos:

• complex_RPC_clnt.c
• complex_RPC_server.c
• complex_RPC_client.c
• complex_RPC.h
• complex_RPC_svc.c
• complex_RPC_xdr.c
• Makefile.complex_RPC

Note que de forma automática se crean los archivos fuente, para que el programador les coloque el
código correspondiente, en este caso a los archivos: complex_RPC_server.c y complex_RPC_client.c;
además, también se crea un archivo de automatización para la compilación del proyecto.

Una vez hecho lo anterior, para compilar todo el proyecto:

$ make -f Makefile.complex_RPC

Para la ejecución del proyecto, empleado la misma maquina por el momento, pero en dos consolas
diferentes, se tiene lo siguiente:
Consola 1 Consola 2
$ ./complex_RPC_server $ ./complex_RPC_client 127.0.0.1

Le ejecución del programa en el servidor hará que se bloque la consola, por lo que el servidor estará a
la espera de solicitudes. Por otra parte, note que el cliente requiere de una dirección IP o nombre de
la máquina, en donde se aloja el procedimiento remoto; en este caso, dado que la ejecución se realiza
en la misma máquina, requerimos de la IP local la cual siempre es 127.0.0.1.

Ejercicios

1. Termine el proyecto de número complejos, para que los procedimientos se ejecuten de manera
remota, pero no localmente, sino en otra máquina. En el laboratorio, las maquinas remotas tienen
dirección IP 172.30.0.1 a 172.30.0.24; también, las puede llamar por su nombre: labred001 a
labred024.
2. Desarrolle los siguientes procedimientos, para que estos puedan ser ejecutados remotamente:

• Búsqueda de cadenas.
• Búsqueda de un número en una lista de números de tamaño N.
• Ordenamiento de una cadena de enteros de tamaño N.
• Factorial de un número N. ¿Se puede implementar de forma recursiva?

Fecha de entrega: pendiente.

También podría gustarte