Está en la página 1de 8

Práctica 4.

RPC
suma.x En los archivos “.x” se definen los prototipos de las funciones que queremos que se publiquen. struct sumandos { int sumando1; int sumando2; }; program PROGRAM_SUMA { version VERSION_SUMA { int suma (sumandos) = 1; } = 1; } = 0x20000001; Para compilar usamos:  $rpcgen -a suma.x

Con la instrucción anterior se generan 7 archivos, sin la opción -a se deja al programador la tarea de crear la implementación misma. Los archivos creados son: 1.- Makefile.suma 2.- suma_xdr.c 3.- suma.h 4.- suma_server.c 5.- suma_svc.c 6.- suma_client.c 7.- suma_clnt.c El archivo suma_xdr.c es para hacer compatibles los tipos de datos con otras arquitecturas. El archivo suma.h contiene los prototipos de las funciones. El archivo suma_server.c es la aplicación del servidor. #include "suma.h" int * suma_1_svc(sumandos *argp, struct svc_req *rqstp) { static int result; /* * insert server code here */ result = argp -> sumando1 + argp -> sumando2; return &result; }

1

#endif /* DEBUG */ } int main (int argc. result_1 = suma_1(&suma_1_arg. PROGRAM_SUMA.c es la interfaz del servidor. if (result_1 == (int *) NULL) { clnt_perror (clnt. } printf("La suma de %d + %d es: %d \n". char *argv[]) { char *host. exit (0). Para ejecutar los programas utilizamos:  $ make -f Makefile. exit (1). program_suma_1 (host). clnt). if (argc < 2) { printf ("usage: %s server_host\n". #ifndef DEBUG clnt_destroy (clnt).sumando2. if (clnt == NULL) { clnt_pcreateerror (host). #ifndef DEBUG clnt = clnt_create (host. } host = argv[1]. "call failed"). #include "suma.sumando1 = 1. suma_1_arg. VERSION_SUMA.suma 2 . sumandos suma_1_arg. "udp").sumando2 = 2.*result_1). } #endif /* DEBUG */ suma_1_arg.El archivo suma_svc. int *result_1. suma_1_arg. exit (1). argv[0]).c es la aplicación del cliente. El archivo suma_client. } El archivo suma_clnt.suma_1_arg.sumando1.c es la interfaz del cliente.h" void program_suma_1(char *host) { CLIENT *clnt.

/suma_client localhost Y finalmente para detener al servidor presionamos la combinación de teclas Ctrl + C. resta. pero en este caso pondremos un servidor local. ya que este programa se está probando en una misma máquina. Realice una aplicación RPC similar a suma./suma_server Abrimos otra terminal (Terminal 2) y escribimos:  $.x que implemente una calculadora con las operaciones de suma. Para hacer referencia a un servicio se utiliza la siguiente estructura: <programa./suma_client <maquina del servidor> donde <maquina del servidor> es la dirección IP del servidor. multiplicación y división. RPC en el nivel medio Los RPC's fueron desarrollados por SUN Microsystems y se apoyan en el protocolo XDR (external Data Representation).Abrimos una terminal (Terminal 1) y escribimos:  $ . procedimiento> Los números de identificación de cada uno de estos están en los siguientes rangos: 0x00000000 – 0x1fffffff -> aplicaciones de SUN 0x20000000 – 0x3fffffff -> Usuario 0x40000000 – 0x5fffffff -> Transitorios de usuario Según el nivel de profundidad en las funciones que se utilizan de RPC se tiene:    Alto Intermedio (solo tres funciones) Bajo A nivel intermedio el cliente utiliza: callrpc -> rpccall 3 . El usuario debe decidir que operación debe hacer. versión. El usuario debe introducir los operandos. AplicaciónRPCa.  $.

const char *nettype). xdrproc_t inproc. xdrproc_t inproc. xdrproc_t outproc. outproc) u_long prognum. En el lado del servidor se utilizan registerrpc() #include <rpc. const u_long versnum. const char *in. const u_long prognum.h> int registerrpc(prognum. svc_run() #include <rpc. u_long versnum. u_long versnum. procname. procnum. versnum.c En una aplicación tradicional se tiene: #include <stdio.Las llamadas al sistema para RPC se ponen a continuación: registerrpc() #include <rpc. u_long procnum. const xdrproc_t outproc. const u_log procnum. char *out. rpc_call() #include <rpc/rpc. inproc.h> svc_run() Tiempo.h> enum clnt_stat rpc_call(const char *host. char *(*procname) (). procname. char *(*procname) (). inproc. procnum. xdrproc_t outproc. versnum. outproc) u_long prognum. u_long procnum. const xdrproc_t inproc.h> int registerrpc(prognum.h> 4 .

char *sresult. exit(0).#include <stdlib. } main() { long lresult. main() { long lresult.h> long bin_date(void ). printf("Hora Local = %s \n".lresult). lresult=bin_date(). char *sresult.h> long bin_date() { long timeval. } Para compilarlo se usa: $gcc Tiempo. printf("Hora Local = %ld \n". } char *str_date(long bintime) { char *ptr. return (ptr). } 5 . #include <stdio. ptr=ctime(&bintime). sresult).c -o Tiempo Cliente. printf("Hora Local = %s \n". timeval=time((long *) NULL). char *str_date(long ). exit(0).h> #include <time. lresult=bin_date(). sresult= str_date(lresult). return (timeval). sresult).c Una evolución será tener dos archivos. printf("Hora Local = %ld \n".h> #include <stdlib.lresult). sresult= str_date(lresult).

return (ptr). #include <stdio. return (&ptr).h #include <rpc/rpc.h> #include <time. return (&timeval). ptr=ctime(bintime).c #include <stdio.h> long bin_date() { long timeval. 6 .h" long *bin_date() { static long timeval. return (timeval).h> #include <time. } char **str_date(long *bintime) { static char *ptr.h> #define DATE_PROG 0x31234567 #define DATE_VERS 1 #define BIN_DATE 1 #define STR_DATE 2 Servidor2.c Servidor.c -o Tiempo Finalmente nuestra aplicación RPC quedaría de la siguiente manera: cl_sv. } char *str_date(long bintime) { char *ptr. timeval=time((long *) NULL). timeval=time((long *) NULL). } Se compila de la siguiente manera:  $gcc Cliente.h> #include "cl_sv.c Una evolución será tener dos archivos.Servidor. ptr=ctime(&bintime).

} main() { registerrpc(DATE_PROG. xdr_long. DATE_VERS. sresult= str_date(lresult). char *str_date(long ). outproc. } long bin_date() { long timeval. DATE_PROG. str_date. xdr_void. xdr_wrapstring). main(int argc.h> #include "cl_sv. xdrproc_t inproc. lresult). xdr_long. DATE_VERS. printf("Hora en %s = %ld \n". registerrpc(DATE_PROG.h> #include <stdlib. bin_date. (char *)(&timeval)).h> #include <string. char *sresult. printf("Hora en %s = %s \n". "Uso: %s hostname \n". xdr_void. STR_DATE. BIN_DATE. lresult=bin_date().h" long bin_date(void ). svc_run(). } Cliente2. DATE_VERS. return timeval. } char *str_date(long bintime) { 7 . if(argc != 2) { fprintf(stderr. callrpc(server. } server=argv[1]. argv[0]). BIN_DATE.c #include <stdio. sresult). char *server. server. char *argv[]) { long lresult. xdr_long). server. exit(0). exit(1). 0.

STR_DATE. (char *)(&ptr)).c -o Servidor2 –l Ejecución del Cliente y servidor: En terminal1:  $. return (ptr). callrpc(server. DATE_PROG. (char *)(&bintime). xdr_long. xdr_long. DATE_PROG./Cliente2 localhost En terminal2:  $. (char *)(&timeval)). BIN_DATE./Cliente2 <dirección IP> Para nuestro ejemplo basta con:  $. DATE_PROG. y en la función str_date(bintime): callrpc(server. DATE_PROG./Servidor2 AplicaciónRPCb. (char *)(&bintime). Para compilar el Cliente hacemos:  $gcc Cliente2. esta aplicación debe ser desarrollada con RPC a nivel medio. DATE_VERS. (char *)(&ptr)). inproc. Crear una aplicación con RPC a nivel medio que simule un chat. // callrpc(server. leer y borrar archivos y directorios de la máquina servidor. Servicio de archivos y directorios. xdr_wrapstring.static char *ptr. (char *)(&ptr)). outproc. (40% de la calificación de la práctica) 8 . (30% de la calificación de la práctica) AplicacionRPCc. Desarrollar un aplicación que permita crear. 0. xdr_wrapstring. STR_DATE. } Para evitar los llamados “warnings” es necesario hacer un cast en la función bin_date(): callrpc(server.c -o Cliente2 -lnsl Para compilar el Servidor hacemos::  $gcc Servidor2. así como cambiar los permisos de estos. (char *)(&bintime). STR_DATE. xdr_long. DATE_VERS. xdr_void. DATE_VERS. DATE_VERS.