Anda di halaman 1dari 12

UNIVERSIDAD NACIONAL AUTNOMA DE NICARAGUA LEN

Dpto. Computacin
Ingeniera Telemtica

Sistemas Distribuidos
Laboratorio 1: Generacin de un programa distribuido con rpcgen.
Objetivo
Esta prctica tiene como finalidad que el alumno sea capaz de crear un programa distribuido
tomando como entrada un programa que originalmente se ejecuta en una mquina local.
Para conseguir este objetivo, se muestra mediante un ejemplo cmo, a partir de un programa local
que visualiza la hora del sistema, se determinan qu procedimiento se ejecutarn de manera
remota y cules de manera local.
Los procedimientos que van a ejecutarse de manera remota van a formar parte de una servicio,
que llamaremos rhora. La interfaz del protocolo de este servicio se describe en el lenguaje XDRL,
y recibe el nombre de rhora.x
Tras someter dicha interfaz al generador rpcgen y basndonos en el conjunto de ficheros
obtenidos en lenguaje C, construiremos un cliente que pida la hora y un servidor que soporte
dicho servicio.
Para finalizar el ejemplo, pondremos en ejecucin el servidor y, mediante un cliente,
comprobaremos que el servidor satisface adecuadamente las peticiones que se le pidan.

La obtencin de la hora
A continuacin vamos a ver, con ms detalles, los pasos que se deben seguir para distribuir una
aplicacin local tomando como ejemplo el programa hora.c
1. Copia, compilacin del programa hora.c
2. Eleccin del conjunto de procedimientos que se situarn en la mquina remota.
3. Creacin de una especificacin en lenguaje XDRL del servicio remoto con nombre rhora.x
4. Compilacin de la interfaz rhora.x para que genere los ficheros correspondientes en
lenguaje C.

5. Escrituras de las rutinas de interfaz del lado del cliente y del servidor.
6. Compilacin y enlace del programa cliente.
7. Compilacin y enlace del programa servidor.
8. Puesta en marcha del servidor y ejecucin del cliente.

Paso 1: Copiar, compilar y ejecutar el programa hora.c en el entorno local.


Como el objetivo de la prctica es clarificar cmo funciona rpcgen, se ha elegido un programa
local muy sencillo que ilustra la mayora de los puntos de inters de la distribucin de una
aplicacin.
Este programa hora.c visualiza por la salida estndar la hora del sistema en formato
hora:minutos.
Para generar el ejecutable hora, compilamos y enlazamos con: gcc o hora hora.c
/*Hora.c*/
#include<stdio.h>
#include <time.h>
//se definen las variables globales del tiempo
struct fecha_t {int anio, mes, dia, hora, minutos;};
struct fecha_t * fechactual;
//Declaramos la variable para los segundos transcurridos desde 1970
time_t segundos;
int result;
int obten_segundos (time_t *s)
{
//Obtencin de los segundos desde el sistema operativo
time(s);
if(s == NULL)
return -1;
else
return 0;
}
struct fecha_t * obten_fecha(time_t * s)
{
struct fecha_t * fecha;
//Declaracin de un puntero a un objeto con la informacin del tiempo
struct tm *puntero_estructura_tiempo;
fecha = (struct fecha_t*) malloc (sizeof(struct fecha_t));
//Actualizacin del objeto estructura de tiempo con los segundos
puntero_estructura_tiempo = localtime(s);
//Estraccin de la informacin desde la estructura tiempo
fecha->hora = puntero_estructura_tiempo->tm_hour;
fecha->minutos = puntero_estructura_tiempo->tm_min;
return fecha;
}

void escribe_hora(struct fecha_t * fecha)


{
printf("Son las %i:%s%i horas\n", fecha->hora, fecha->minutos <10 ?"0": " ", fecha->minutos);
}
main()
{
result = obten_segundos(&segundos);
if(result == -1)
{
printf("Hora.c: error en la llamada time\n");
exit(1);
}
fechactual=obten_fecha(&segundos);
escribe_hora(fechactual);
}

Paso 2: Eleccin de procedimientos que se situarn en la mquina remota.


Una vez que la aplicacin local funciona correctamente, se puede particionar en componentes
remotos y locales. La organizacin procedural de la aplicacin local es la siguiente:

hora.c
main

obten_segundos

obten_fecha

escribe_hora

Mquina Local
A la hora de considerar qu procedimientos se pueden mover a una mquina remota, hay que
tener en cuenta los recursos que necesitar cada procedimiento. Por ejemplo, escribe_hora
accede a al salida estndar del proceso (la pantalla) por lo que este procedimiento debera
permanecer local. En general: es difcil mover a una mquina remota procedimientos que realizan
operaciones de entrada/salida o manejan descriptores de ficheros locales.
Tambin hay que considerar la ubicacin de los datos a los que accede cada procedimiento.
Aunque no es ste el caso, podra haber una aplicacin que gestionara un diccionario a travs de
procedimientos, que actuaran sobre una gran base de datos. Parece razonable pensar que si los
procedimientos se ubican remotamente, la base de datos debera ubicarse en el mismo servidor
que los procedimientos, para evitar transmitir por la red el contenido de la base de datos. En

general: los procedimientos deben situarse en la misma mquina donde se ubican los datos sobre
los que actan ya que la transmisin de estructuras grandes de datos como argumentos es
ineficaz.
Por ltimo, hay que observar si los procedimientos contienen llamadas al sistema locales. Si se
decide que sean remotas y el sistema operativo remoto no soporta la misma interfaz de llamadas,
habr que sustituir las antiguas llamadas locales por las que soporte el nuevo sistema operativo
sobre el que acte el procedimiento.
En este caso, se da esta circunstancia tanto en el procedimiento obten_segundos que invoca a la
llamada time y en el procedimiento obten_fecha que usa la llamada local_time.
Como el inters de nuestro programa es obtener una hora fiable de un servidor de tiempos, con
hacer remoto el procedimiento obten_segundos es suficiente, ya que la conversin a un formato
horario es mejor hacerlo localmente. La mquina destino cuenta con el mismo sistema operativo
que la mquina local, por lo que la llamada al sistema time de obten_segundos se puede ejecutar
correctamente en la mquina remota. As, la divisin de procedimientos entre las dos mquinas
quedara:

rhora.c
main

escribe_hora

obten_fecha

RPC
rhora_srp.c
obten segundos

Mquina Local

Mquina Remota

Una vez realizada la divisin de los procedimientos, el siguiente paso es dividir el programa inicial
hora.c en dos componentes. Se seleccionan las constantes y estructuras de datos que usar cada
parte situndolas en ficheros separados. En la mquina local, el fichero rhora.c contendr
exactamente lo mimo que el programa local hora.c excepto la declaracin y el cuerpo del
procedimiento remoto obten_segundos.
El fichero rhora_srp.c (source remote procedure) contiene la declaracin y el cuerpo del
procedimiento que obtiene los segundos del sistema.

Paso 3: Especificacin en lenguaje XDRL del servicio rhora.x


Una vez que el programador selecciona el conjunto de procedimientos que se ejecutarn
remotamente, ha que preparar la especificacin de la interfaz, que recoger dichos
procedimientos, en un lenguaje que entienda el compilador de interfaces rpcgen. Este lenguaje,
que no es C aunque se le parece bastante, se llama XDRL.
La especificacin contendr las declaraciones de constantes, tipos de datos y perfiles de los
procedimientos que el servidor ofrecer a los clientes.
A un fichero que contiene la especificacin de un servicio en lenguaje XDRL se la asigna la
extensin .x
As, el fichero rhora.x recoge la especificacin del servicio de hora remota.
/*rhora.x*/
enum horastat{
HORA_OK = 0, /*no error*/
HORA_NOK = 1 /*error*/
};
/*valor de la hora*/
union segactual switch(horastat status){
case HORA_OK:
long segundos;
default:
void;
};
/*Procedimiento remoto de la hora*/
program HORA_PROGRAM{
version HORA_VERSION{
segactual OBTEN_SEGUNDOS(void) = 1;
}=1;
}=0x30; /*Aqu se pone un valor distinto por el alumno*/

Por convenio se usan letras maysculas para representar los nombres de procedimientos y del
programa.
Hay que destacar que el procedimiento OBTEN_SEGUNDOS se ha diseado para que solo tenga
un parmetro de salido. Y ese parmetro es un registro variable que, dependiendo del valor de la
etiqueta status, devolver un valor u otro:

status = HORA_OK indica que el servidor ha realizado el servicio con xito y, por tanto, el
campo segundos contendr los segundos pedidos.

status

= HORA_NOK indica que se ha producido un error en la ejecucin del

procedimiento remoto, por lo que no habr informacin en el registro.


Por ltimo, el nmero del programa asignado al servidor debe ser nico para cada programa. De
esta forma podemos tener varios servidores corriendo a la vez en el mismo ordenador y los
clientes tendrn una forma de referenciarlos. Si se usara el mismo nmero, solo podra registrarse
un servidor (el primero en arrancarse) y no ser posible que cada alumno depurara su propio
servidor.

Paso 4: Compilacin de la interfaz rhora.x


Una vez modificado adecuadamente el nmero de programa en rhora.x se le someter al
compilador de interfaces rpcgen: rpcgen C rhora.x
La opcin C genera cdigo compatible con ANSI C o C estndar.
Esta compilacin comprueba errores sintcticos y, si nos los encuentra, genera los siguientes
ficheros en C:

rhora_clnt.c: stubs del cliente

rhora_svc,c: stub del servidor

rhora_xdr.c: procedimientos que convierten a/desde formato local desde/a formato externo
los tipos de datos declarados en rhora.x

rhora.h: declaraciones de constantes y tipos en c contenidos en el fichero de


especificacin, as como los perfiles de la funcin obten_segundos para el cliente y el
servidor.

Paso 5: Escritura de las rutinas de interfaz


Como ya se ha comentado, en el lado del cliente seguir estando el programa principal rhora.c.
Este programa llama al procedimiento obten_segundos con el mismo parmetro. No hay que
olvidar que en el paso 2 hemos situado el cuerpo de este procedimiento en la mquina remota.
Por otra parte, como resultado de someter la especificacin del servicio rhora.x al compilador
rpcgen se obtiene, entre otros, el stub del lado del cliente del procedimiento obten_segundos_1
(fichero rhora_clnt.c). Este procedimiento es el que realiza desde el lado del cliente la llamada al
procedimiento remoto que devuelve los segundos pedidos. Por tanto, desde el programa principal,
sin modificar el cdigo original, se tendra que invocar el procedimiento obten_segundos_1. Pero

no es posible, ya que el procedimiento llamado desde el programa principal no concuerda con el


ofrecido por el stub pues obten_segundos y obten_segundos_1 no se llaman igual. Obsrvese
que el procedimiento generado por rpcgen acaba con el sufijo _1. Este sufijo indica la versin 1
del servicio. El problema no acaba aqu, no solo no se llaman igual, sino que adems tienen
diferentes tipos de parmetros como se muestra a continuacin:
//declaracin de obten_segundos en rhora.c
int obten_segundos (time_t *s);
//declaracin de obten_segundos_1 en rhora_clnt.c
segactual * obten_segundos_1(void *argp, CLIENT *clnt);

Hay una solucin: escribir en la mquina local, el cuerpo del procedimiento obten_segundos para
sea ste el que llame al procedimiento del stub obten_segundos_1 con los parmetros adecuados
y recoja el resultado de obten_segundos_1 para devolverlo al programa principal, de acuerdo al
tipo de resultado que ste espera. Es decir, todo este proceso de adaptacin de los parmetros
entre el programa principal y el procedimiento del stub del cliente obten_segundos_1 se recoge
dentro del procedimiento obten_segundos.
Por convenio, este procedimiento se conoce como rutina de interfaz del cliente y le vamos a incluir
en el fichero rhora_cif.c (client interfaces).
Grficamente, el esquema de llamada es:

rhora.c
main()
{

obten_segundos();

rhora_cif.c
.
int obten_segundos(time_t *s)
{
prepara_parmetros
obten_segundos_1(parmetros)
recoge resultados
}

rhora_clnt.c
segactual *
obten_segundos_1(void
*argp, CLIENT *clnt)
{
..
Aqu se hace la RPC
}

Adems, para que esta rutina de interfaz sea capaz de realizar una llamada remota al servidor es
necesario crear un cliente del servicio de tiempo con la rutina clnt_create que ofrece la librera rpc.
Por eso es necesario hacer #include <rpc/rpc.h>.
Los parmetros que se necesitan para crear un cliente son: el nombre de la mquina donde reside
el servidor de hora, el nombre de programa del servicio HORA_PROGRAM y HORA_VERSION y
el protocolo de comunicacin. Nosotros utilizaremos udp.
Con todas estas consideraciones, el cdigo de la runita de la interfaz del cliente podra ser el
siguiente:
//rhora_cif.c
#include <time.h>
#include <rpc/rpc.h>
#include "rhora.h"
#define Rmaquina "localhost"
static CLIENT *clte_rhora;
int obten_segundos(time_t *s)
{
struct segactual *segundos;
//se crea un cliente del servicio de hora
clte_rhora = clnt_create(Rmaquina, HORA_PROGRAM, HORA_VERSION, "udp");
if(clte_rhora == NULL)
return -1;
segundos = (struct segactual*) malloc (sizeof(struct segactual));
//se realiza la rpc
segundos = obten_segundos_1(NULL, clte_rhora);
if(segundos == NULL) //error de comunicacin con el servidor
return -1;
else if (segundos->status == HORA_NOK) //error de ejecucin
return -1;
else // se recogen los segundo devueltos
*s = (time_t)segundos->segactual_u.segundos;
}

Con el procedimiento anterior hay que destacar que cuando hay un error en la conexin o bien en
el servidor devuelve un error, el procedimiento enmascara el error de comunicacin devolviendo
un -1, para que el programa principal siga viendo la llamada si se ejecutara localmente.
Rutinas de interfaz del lado del servidor: rhora_sif.c
En el lado del servidor ocurre algo similar a lo que ocurre en el lado del cliente. El servidor, que
ejecuta el programa rhora_svc.c, se encarga de recibir peticiones procedentes de los clientes,
analizar la peticin a realizar, e invocar el procedimiento que lleva a cabo dicha peticin.

En nuestro caso, cuando el servidor reciba la peticin de obtencin de la hora en segundos, ste
invoca el procedimiento del stub obten_segunods_1_svc. Como se puede observar, surge el
mismo problema que apareci en el apartado anterior: este procedimiento no se llama igual que el
procedimiento obten_segundos (que incluimos en el paso 2 en el fichero rhora_srp.c) ni cuenta
con los mismos parmetros.
//declaracin de obten_segundos en rhora_srp.c
int obten_segundos (time_t *s);
//declaracin de obten_segundos_1_svc en rhora_clnt.c
segactual * obten_segundos_1_svc(void *p1, struct svc_req *p2);

La solucin se basa en usar la misma idea aplicada en el apartado anterior: hay que escribir un
cuerpo del procedimiento obten_segundos_1_svc que invoque adecuadamente al procedimiento
obten_segundos, recoja el valor devuelto por este procedimiento, lo analice y, finalmente
construya una respuesta que est de acuerdo con lo que espera el programa rhora_svc.c
La declaracin y el cuerpo de este procedimiento debe guardarse en el fichero rhora_sif.c (Server
interface file). Grficamente:

rhora_svc.c
main()
{

obten_segundos_1_svc();

rhora_sif.c
segactual *
obten_segundos_1_svc()
{
prepara_parmetros
obten_segundos(..)
recoge resultados

rhora_srp.c

int obten_segundos_1_svc
(time_t *s)
{
Aqu se hace la llamada local

Time(&s);
}

El cdigo de la rutina de la interfaz del servidor podra ser el siguiente:


//rhora_sif.c
#include <time.h>
#include <stdio.h>
#include <rpc/rpc.h>
#include <time.h>
#include "rhora.h"
extern segactual * obten_segundos_1_svc(void *p1, struct svc_req *p2)
{
int resultado;
time_t s;
segactual *segundos_actuales;
//se reserva espacio para almacenar el resultado
segundos_actuales = (segactual *) malloc (sizeof(struct segactual));
//Se llama al procedimiento local
resultado = obten_segundos(&s);
if(resultado == -1) //error de ejecucin del procedimiento local
segundos_actuales->status = HORA_NOK;
else //el procedimiento local se ejecut correctamente
{
segundos_actuales->status = HORA_OK;
segundos_actuales->segactual_u.segundos = s;
}
return segundos_actuales;
}

Paso 6: Compilacin y enlace del programa cliente rhora


Se compilan los siguientes ficheros:
gcc c rhora_cif.c
gcc c rhora.c
gcc c rhora_clnt.c
gcc c rhora_xdr.c
Se enlazan todos estos ficheros en un solo ejecutable que ser el cliente rhora:
gcc o rhora rhora.o rhora_cif.o rhora_clnt.o rhora_xdr.o
El diagrama de fichero que se usan para generar el programa del cliente es el siguiente:

rhora_clnt.c

rhora.x

rpcgen

rhora.h

rhora_xdr.c

rhora.c

rhora_cif.c

Compilador
C

rhora
10

Paso 7: Compilacin y enlace del programa servidor rhorad


Se compilan los siguientes ficheros:
gcc c rhora_sif.c
gcc c rhora_srp.c
gcc c rhora_svc.c
gcc c rhora_xdr.c
Se enlazan todos estos ficheros en un solo ejecutable que ser el servidor rhorad:
gcc o rhorad rhora_svc.o rhora_sif.o rhora_srp.o rhora_xdr.o
El diagrama de fichero que se usan para generar el programa del servidor es el siguiente:

rhora_svc.c

rhora.x

rhora_srp.c

rhora.h

rpcgen

rhora_sif.c

Compilador
C

rhora_xdr.c

rhorad

Paso 8: Puesta en marcha del servidor y ejecucin del cliente


El servidor debe empezar a ejecutarse antes que el cliente, para evitar errores como este:
Servidor: RCP: Program not registered
En un sistema Unix se arranca el servidor con el siguiente comando: ./rhorad &
Este comando arranca el servidor en un segundo plano (background) y deja el Terminal libre para
suministrarle otros comandos. Hay que anotar el nmero del proceso pid que aparece, por si
queremos matar al servidor con el comando:
kill -9 pid

11

Trabajo asignado:
1. Ejecute en primer lugar el programa hora.c en un entorno local.
2. Siga cada uno de los pasos descritos en esta prctica, para convertir al programa hora en
una aplicacin distribuida.
3. Pruebe en primer lugar el cliente y el servidor en la misma mquina y luego en mquinas
diferentes.
4. Cree un fichero Makefile, para hacer menos pesada la organizacin de los ficheros que
intervienen en la aplicacin distribuida. Pruebe este fichero.

Plazo de realizacin:
Dos sesiones de Laboratorio.

12

Anda mungkin juga menyukai