Ejemplos java y C/linux

Tutoriales

Enlaces

Licencia

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Para reconocer la autoría debes poner el enlace http://www.chuidiang.com

RPC (Remote Procedure Call)

Concepto de RPC

En unix es posible tener en ejecución un programa en C con varias funciones que pueden ser llamadas desde otro programas. Estos otros programas pueden estar corriendo en otros ordenadores conectados en red.

Supongamos, por ejemplo, que tenemos un ordenador muy potente en cálculo matemático y otro con un buen display para gráficos. Queremos hacer un programa con mucho cálculo y con unos gráficos "maravillosos". Ninguno de los dos ordenadores cumple con ambos requisitos. Una solución, utilizando RPC (Llamada a procedimientos remotos), consiste en programar las funciones matemáticas en el ordenador de cálculo y publicar dichas funciones. Estas funciones podrán ser llamadas por el ordenador gráfico, pero se ejecutarán en el ordenador de cálculo. Por otro lado, hacemos nuestros gráficos en el ordenador gráfico y cuando necesitemos algún cálculo, llamamos a las funciones del ordenador de cálculo.

Al programa con las funciones se le llama "servidor". Al programa que llama a esas funciones se le llama "cliente". Normalmente el servidor está siempre corriendo y a la espera de que algún cliente llame a alguna de sus funciones.. Cuando el cliente llama a una función del servidor, la función se ejecuta en el servidor y el cliente detiene su ejecución hasta que el servidor termina.

En el código del programa servidor básicamente hay que seguir los siguientes pasos:

Mientras que el programa cliente debe:

EL PROGRAMA RPCGEN

Afortunadamente en unix existe una utilidad llamada rpcgen que nos ayuda en todo el proceso de codificación. En un lenguaje similar a C (pero no igual) definimos los prototipos de las funciones que queremos que se publiquen. Habitualmente dicho fichero suele tener la extensión ".x". Luego, con el comando de unix

rpcgen -a fichero.x

se generan varios ficheros (7 en concreto) con todo el código hecho, excepto, naturalmente, el código de las funciones que queremos publicar.

Si no ponemos la opción -a, se generarán menos ficheros, dejándonos a nosotros el trabajo de generar los siguientes. El motivo es que sin la opción -a se generan únicamente los ficheros con las funciones (vacias, para que las rellenemos). Con la opción -a se generan además unos ejemplos de uso, que pueden ser útiles siempre y cuando estemos dispuestos a modificarlos. En el resto del texto suponemos siempre que se ha usado la opción -a.

El servidor que genera rpcgen tiene todo prácticamente hecho, con la excepción de que nuestras funciones están casi vacias (devuelven un valor por defecto). Tenemos que editar y rellenar el código de nuestras funciones.

El cliente que genera rpcgen tiene también todo hecho. Se conecta al servidor, llama a todas las funciones una por una y cierra la conexión. Obviamente aprovechamos el principio (la conexión) y el final (la desconexión). Las llamadas a las funciones deberíamos borrarlas y hacer que el cliente haga lo que nosostros queramos.

Veamos un pequeño ejemplo de un fichero.x

program  NOMBRE_PROGRAMA {
    version VERSION_PROGRAMA {
        int incrementa (int) = 1;
    } = 1;
} = 0x20000001;

El fichero comienza con la palabra "program" y el nombre que queramos dar a nuestro programa. Después, entre llaves va el resto. Al final todo se iguala a un número (= 0x20000001; ). Este número debe ser único para cada programa. De esta forma podemos tener varios servidores corriendo a la vez en el mismo ordenador y los clientes tendrán una forma de referenciarlos.

Dentro de las llaves del programa va "version" con el nombre de la version y, después de la estructura de llaves, igualado a un número de versión ( = 1; ). Esto permite tener corriendo varias versiones del mismo programa (y de las mismas funciones) a la vez. Los clientes pueden indicar a qué versión quieren llamar.

Finalmente, dentro de las llaves de versión, van los prototipos de nuestras funciones. Cada función se iguala a un número ( = 1; ) distinto, de forma que el cliente referenciará a la función por su número. Todas las funciones deben admitir un único parámetro. Si queremos pasar más de un parámetro, deberemos hacernos una estructura con los campos necesarios. Lo mismo pasa con el retorno de la función, puede ser un tipo simple o una estructura.

El lenguaje admite la declaración de estructuras para pasar parámetros complejos. Si queremos una función que admita varios parámetros, debemos hacer una estructura con todos esos parámetros. La función admitirá como único parámetro una estructura de este tipo.

Por ejemplo, si nuestra función es "int suma (int sumando1, int sumando2);", el fichero suma.x debería contener algo parecido a lo siguiente:

struct sumandos
{
     int sumando1;
     int sumando2;
};

program PROGRAMA_SUMA {
    version VERSION_SUMA {
        int suma (sumandos) = 1;
    } = 1;
} = 0x20000001;

Ficheros generados por rpcgen

Una vez escrito nuestro fichero suma.x, hacemos una llamada al comando de unix "rpcgen -a suma.x". Esto generará 7 ficheros distintos (Puedes "pinchar" el nombre del fichero para verlo. Si lo descargas, quítale la extensión ".txt").

Para ejecutar el ejemplo...

El ejemplo crea un servidor que publica una función de sumar dos enteros. Luego un cliente se conecta, pide una suma al servidor pasándole dos enteros y escribe el resultado en pantalla.

Debes descargar todos los ficheros mencionados en un directorio. Luego compilas con "make -f Makefile.suma", con lo que se generan dos ejecutables: suma_server y suma_client. Ejecutas el servidor desde una shell con "suma_server". Luego ejecutas el cliente con "suma_client <maquina_servidor>" y ves el resultado. <maquina_servidor> es el nombre de la máquina donde has ejecutado el suma_server. Si es en la misma máquina, puedes poner de nombre de máquina "localhost".

En este video puedes ver todo el proceso:

Estadísticas y comentarios

Numero de visitas desde el 4 Feb 2007: