Tema 6
Llamadas a procedimientos remotos
F. García-Carballeira, Mª. Soledad Escolar,
Contenidos
Remote Procedure Call
(RPC)
Conceptos básicos
Aspectos relacionados con las RPCs
RPC
de
Sun Microsystems
Biblioteca
de funciones de RPC
Biblioteca
de funciones de RPC
Compilar un programa
Ejemplo
de RPC
RPC
RPC
(
Remote Procedure Call
): llamadas a procedimientos
remotos
Por
Birrel
y
Nelson
(
1985
) en “Implementing Procedure Calls”
Híbrido:
Llamadas a procedimientos en local
Paso de mensajes
Paso de mensajes
Las RPC constituyen el
núcleo
de muchos SSDD
Llegaron a su culminación con DCE (
Distributed Computing
Environment
)
Han evolucionado hacia orientación a objetos
RPC
Las RPCs
ofrecen una interfaz sencilla para construir aplicaciones
distribuidas sobre TCP/IP
RMI and
RPC
Aplicaciones/servicios
Sockets
Aplanamiento (marshalling), representación externa
de datos
Protocolo de transporte
RPCs en la pila de protocolos
RPC:
En el nivel de sesión en OSI
En el nivel de aplicación en
TCP/IP
Independientes del
RPC
Independientes del
protocolo de transporte
TCP
UDP
Fiabilidad no garantizada
Depende del protocolo de
RPC de Sun Microsystems
La versión 2 de RPC, descrita en la RFC 1057, fue estandarizada por
Sun
Microsystems
Se ocupa:
Especificación e interpretación de mensajes
NO
se ocupa:
Cómo se realiza el intercambio de mensajes entre los procesos
Restricciones de la capa de transporte utilizado
Binding
entre un cliente a un servicio
Binding
entre un cliente a un servicio
La
sintaxis
y el
formato de los mensajes
se define mediante IDL
(Interface
Definition Language):
Lenguaje de especificación de RPC
Comunicación cliente-servidor
Protocolo petición-respuesta
Mensaje de petición
Solicitar
operación
Recibir petición
Seleccionar servicio
Servidor
Cliente
(esperar)
(continúa)
Mensaje de respuesta
Ejecutar servicio
Seleccionar servicio
Estructura de los mensajes
petición-respuesta
Id. De petición
Id. De operación
argumentos
Funcionamiento de las RPC
El proceso que realiza la llamada
empaqueta los argumentos
en un
mensaje
,
se los envía a otro proceso y
espera el resultado
El proceso que ejecuta el procedimiento
extrae los argumentos
del
mensaje,
realiza la llamada
de forma local, obtiene el resultado y se lo
envía
de vuelta
al proceso que realizó la llamada
Objetivo:
acercar la semántica de las llamadas a procedimiento
convencional a un entorno distribuido (transparencia)
main(){
...
r = sumar (4, 5);
...
}
sumar(int a, int b)
Llamada local
main(){
...
r = sumar (4, 5);
...
}
sumar(int a, int b)
int r;
r = a + b;
Pila del proceso
r = a + b;
return r;
}
Registro de activación
r
b
a
Llamada a procedimiento remoto
main(){
...
r = sumar (4, 5);
...
}
a
Dir retornob
c
Cliente
servidor
Stub
sumar(int a, int b)
send(a, b);
receive(r);
main(){
receive (4, 5)...
r = sumar (4, 5);
send (r)
}
sumar(int a, int b)
int r;
Conceptos básicos
Una RPC tiene dos participantes:
Un
cliente activo
, que envía una RPC al servidor
Un
servidor pasivo
, que calcula un resultado y lo devuelve al cliente
Un servicio de red es una colección de uno o más programas remotos
Un programa remoto implementa uno o más procedimientos remotos
Un servidor puede soportar más de una versión de un programa remoto
Un servidor puede soportar más de una versión de un programa remoto
Permite al servidor ser compatible con las
actualizaciones de protocolos
Un procedimiento remoto, sus parámetros y sus resultados se
Suplentes (
stubs
)
Se
generan
automáticamente
por el software de RPC
Stub del cliente
Stub del sevidor
Un stub
es una pieza de código usada en el cliente y el servidor
Responsable de
convertir los parámetros
de la aplicación cliente/servidor
durante una llamada a procedimiento remoto
Cliente
Servidor Stub
Stub
durante una llamada a procedimiento remoto
Espacio de direcciones independiente del cliente y servidor
Representaciones de datos diferentes (big-endian, little-endian)
Los suplentes son independientes
de la implementación que se haga del
cliente y del servidor.
Suplentes (
stubs
)
Funciones en el
cliente
:
Suplantar al procedimiento a ejecutar
Localizar al servidor
Empaquetar los parámetros y construir los mensajes
Enviar el mensaje al servidor
Esperar la recepción del mensaje y devolver los resultados
Cliente
Servidor Stub
Stub
Esperar la recepción del mensaje y devolver los resultados
Funciones en el
servidor:
RPC: protocolo básico
cliente
servidor
Se registra en un
servicio de nombres
Recibir la petición
localizar al
servidor
preparar
parámetros,
enviar petición
Desempaquetar
la respuesta
Recibir la petición
Ejecutar el
procedimiento
Preparar la respuesta
y enviar
RPC: protocolo básico
Máquina servidora
Máquina cliente
Protocolo
Proceso cliente
(llamador)
Proceso servidor
(llamado)
Protocolo
petición-respuesta
Proceso cliente (llamador)
Conectar
al servidor
Invocar
una llamada a
procedimiento remoto
Stub
o resguardo del cliente:
Máquina cliente
Proceso cliente
(llamador)
RPC: protocolo básico
Localizar al servidor
Empaquetar los parámetros y
construir los mensajes
Enviar los mensajes al servidor
Bloquearse hasta esperar la
respuesta
Obtener
la respuesta
RPC: protocolo básico
Máquina servidora
Proceso servidor
(llamado)
Registrar
las RPCs
Implementar
los procedimientos
Stub
o resguardo del servidor:
Recibir la petición del cliente
Proceso servidor (llamado)
Stub
Recibir la petición del cliente
Desempaquetar los parámetros
Invocar el procedimiento de manera
local
Obtener
la respuesta y enviarla al
Modelos de RPCs
RPCs síncronas
RPC asíncronas
El cliente
no
espera la respuesta
No admite parámetros de salida
Ejemplo en CORBA:
Se corresponden con métodos especificados como
oneway
cliente
servidor
cliente
servidor
localizar al
servidor
preparar
parámetros,
enviar petición
Se registra en un
servicio de nombres
Recibir la petición
Aspectos relacionados con las RPC
Lenguaje de definición de interfaces (
IDL
)
Generador de
stubs
Tipos de
parámetros
Transferencia de parámetros
Protocolo
de comunicación
Protocolo
de comunicación
Enlace
entre el cliente y el servidor (
binding
)
Semántica de las RPC en presencia de fallos
Un Lenguaje de Definición de Interfaz (IDL) permite especificar el
formato
de los
procedimientos remotos
y otras
opciones de comunicación
La interfaz es compartida por
Cliente
Servidor
Cliente
Servidor Stub
Lenguaje de Definición de Interfaces
<opciones de comunicación:
versión interfaz, tcp/udp, …
>
<interfaz remota:
suma (in int a, in int b, out int c) ;
>
generador
STUB
Una interfaz
especifica:
Nombre de servicio
que utilizan los clientes y servidores
Nombres de procedimientos
Parámetros de los procedimientos
Entrada
Salida
Tipos de datos
de los argumentos
Lenguaje de Definición de Interfaces
Tipos de datos
de los argumentos
Los compiladores pueden diseñarse para que los clientes y servidores se
escriban en lenguajes diferentes
Tipos de IDL
Integrado con un lenguaje de programación (Cedar, Argus)
Lenguaje de definición de interfaces específico para describir las interfaces entre
Tipos de parámetros
Parámetro
de entrada
(
in
)
El parámetro se envía del cliente al servidor
Parámetro
de salida
(
out
)
Transferencia de parámetros
Una de las funciones de los suplentes es
empaquetar los
parámetros en un mensaje
:
aplanamiento
(
marshalling
)
Problemas
en la representación de los datos:
Servidor y cliente pueden ejecutar en máquinas con
arquitecturas
distintas
(ordenamiento de bytes)
Problemas con los punteros
Una dirección sólo tiene sentido en un
espacio de direcciones
Una dirección sólo tiene sentido en un
espacio de direcciones
Ejemplos de esquemas de representación de datos:
XDR
(
eXternal Data Representation
) es un estándar que define la
representación de tipos de datos (
RFC 1832
)
Representación común de datos de CORBA (
CDR
)
Serialización de objetos de Java
Ejemplo de representación de datos
Mensaje: ‘Smith’, ‘London’, 1934
0–3
4–7
8–11
12–15
5
"Smit"
"h___"
6
index in
sequence
of bytes
4 bytes
notes
length of string
‘Smith’
length of string
XDR
CDR
16–19
20-23
24–27
"Lond"
"on__"
1934
‘London’
unsigned long
<
person
>
<
name
>Smith</
name
>
<
place
>London</
place
>
<
year
>1934</
year
>
</
person
>
Protocolo
Entre
cliente
y
servidor
debe establecerse un
protocolo
:
Formato de los mensajes
Enlace
(Binding)
Enlace
: asociación entre el cliente y el servidor
Implica
localizar al servidor
que ofrece un determinado
servicio
El servidor debe
registrar su dirección
en un servicio de
Enlazador dinámico
Enlazador dinámico (binder)
: es el
servicio
que mantiene
una
tabla de traducciones
entre
nombres de servicio
y
direcciones
.
Incluye funciones para:
Registrar un nombre de servicio
Eliminar un nombre de servicio
Eliminar un nombre de servicio
Buscar la dirección correspondiente a un nombre de servicio
Cómo
localizar
al enlazador dinámico:
1.
Ejecuta en una dirección fija de un computador fijo
2.
El sistema operativo se encarga de indicar su dirección
3.
Difundiendo un mensaje (
broadcast
) cuando los procesos comienzan su
1
5
Esquema de registro y enlace
cliente
servidor
1
3
4
6
7
2
1
Obtiene dirección
binder
3
2
Registra dirección
3
Busca servidor
4
Devuelve dirección
5
Petición
Tipos de enlace
Enlace
no persistente
:
el binding
entre el cliente y el
servidor
se establece en cada RPC
Más tolerante a fallos
Permite migración de servicios
Enlace
persistente
:
el binding se mantiene
después de la
Enlace
persistente
:
el binding se mantiene
después de la
primera RPC
Útil en aplicaciones con muchas RPC repetidas
Problemas si lo servidores cambian de lugar
Fallos que pueden aparecer con las RPC
El cliente no es capaz de localizar al servidor
Pérdidas de mensajes
Se pierde el mensaje de petición del cliente al servidor
Se pierde el mensaje de respuesta del servidor al cliente
El servidor falla después de recibir una petición
El servidor falla después de recibir una petición
Cliente no puede localizar al servidor
Posibles causas:
El servidor puede estar caído
El cliente puede estar usando una
versión antigua
del servidor
La versión ayuda a detectar accesos a copias obsoletas
Cómo indicar el
error
al cliente
Cómo indicar el
error
al cliente
Devolviendo un
código de error
(
-1
)
No es transparente
Ejemplo: sumar(a,b)
Elevando una excepción
Pérdida de mensajes del cliente
Es la más fácil de tratar
Se activa una alarma (
timeout
) después de enviar el
mensaje
Si pasado el timeout no se recibe una respuesta se
Pérdidas en los mensajes de respuesta
Más
difícil
de tratar
Se pueden emplear alarmas y retransmisiones, pero:
¿Se perdió la petición?
¿Se perdió la respuesta?
¿El servidor va lento?
Algunas
operaciones pueden repetirse
y devolverán el mismo resultado
(operaciones idempotentes)
(operaciones idempotentes)
Una transferencia bancaria
no
es
idempotente
La suma de dos números es
idempotente
La solución con operaciones no idempotentes
es
descartar peticiones
ya ejecutadas
Un
número de secuencia
en el cliente
Un
campo en el mensaje
que indique si es una petición
original
o una
Fallos en los servidores
El servidor no ha llegado a ejecutar la operación
Se podría retransmitir
El servidor ha llegado a ejecutar la operación
El cliente no puede distinguir los dos
¿Qué hacer?
No garantizar nada
No garantizar nada
Semántica
al menos una vez
Reintentar y garantizar que la RPC se realiza al menos una vez
No vale para operaciones
no idempotentes
Semántica
a lo más una vez
No reintentar, puede que no se realice ni una sola vez
Semántica
de exactamente una
Fallos en los clientes
La computación está activa pero ningún cliente espera los
resultados (
computación
huérfana
)
Gasto de ciclos de CPU
Si el cliente rearranca y ejecuta de nuevo la RPC se pueden
Estrategias ante fallos
Cliente RPC:
Cuando no se recibe la respuesta
Reenviar
la petición
Incluir identificador de petición (número de secuencia)
Servidor RPC:
Servidor RPC:
Para hacer frente a peticiones duplicadas
Filtrar
las peticiones (números de secuencia, etc.)
Si se necesita reenviar una respuesta de una petición
no
idempotente
:
Guardar un histórico de las peticiones anteriormente ejecutadas y su
Aspectos de implementación
Protocolos RPC
Orientados a conexión
Fiabilidad se resuelve a bajo nivel
Peor rendimiento
No orientados a conexión
Uso de un protocolo estándar o uno específico
Uso de un protocolo estándar o uno específico
Programación con un paquete de RPC
El programador debe proporcionar:
La
definición de la interfaz
(IDL)
Nombres de los procedimientos
Parámetros
que el cliente pasa al servidor
Resultados
que devuelve el servidor al cliente
El
código del cliente
El
código del cliente
El
código del servidor
Desarrollo de la aplicación con RPC
DESARROLLO
DE LA
INTERFAZ
COMPILADOR IDL
SUPLENTE EN SERVIDOR SUPLENTE EN CLIENTE CABECERA FICHERO DE DEFINICIÓN DE INTERFAZCOMPILADOR C COMPILADOR C
COMPILADOR C COMPILADOR C CABECERA CABECERA FICHEROS FUENTE DEL CLIENTE FICHEROS OBJETO DEL CLIENTE FICHEROS OBJETO DEL SERVIDOR EJECUTABLE DEL CLIENTE EJECUTABLE DEL SERVIDOR FICHEROS FUENTE DEL SERVIDOR OBJETO SUPLENTE EN CLIENTE OBJETO SUPLENTE EN SERVIDOR MONTADOR MONTADOR BIBLIOT. RPC BIBLIOT. RPC
DESARROLLO
DEL
DESARROLLO
@Fuente: Jesús Carretero,
Félix García, Pedro de Miguel y Fernando Pérez.
RPC de SUN Microsystems
Diseñado para el sistema de ficheros NFS
Descrito en RFC 1831
También se denomina ONC-RPC
(
Open network computing
)
Se puede elegir
UDP
o
TCP
Cliente y servidor deben estar de acuerdo en el protocolo de transporte a
utilizar
Utiliza la
semántica
al menos una vez
Utiliza la
semántica
al menos una vez
Utiliza un lenguaje de definición de interfaces denominado XDR
Soporte:
Para C a través del compilador rpcgen
en UNIX/Linux
Para Java
RPC de SUN y el modelo OSI
aplicación
XDR
RPC
7. Aplicación
6. Presentación
5. Sesión
TCP
UDP
IP
Interfaz HW
4. Transporte
3. Red
Lenguaje XDR
XDR (eXternal
Data Representation) es un estándar que define la representación de
tipos de datos (RFC 1832)
Utilizado inicialmente para
representaciones externas de datos
Se extendió a
lenguajes de definición de interfaces
Una
interfaz
contiene:
Un
número de programa
Un
número de versión
del programa
Un
Un
conjunto de procedimientos remotos
conjunto de procedimientos remotos
:
:
Un
nombre
y un
número de procedimiento
Los procedimientos sólo aceptan
un parámetro de entrada
(se encapsulan en una
estructura)
Los parámetros de salida se devuelven mediante
un único resultado
El lenguaje ofrece una notación para definir:
constantes
Formato de definición de interfaz
program-def
:
"program" identifier "{"
version-def
version-def
*
"}" "=" constant ";“
/* Number of program */
version-def
:
"version" identifier "{"
procedure-def
procedure-def
*
"}" "=" constant ";"
/* Number of version */
procedure-def
:
type-specifier identifier "(" type-specifier
("," type-specifier )* ")"
Ejemplo:
especificación del programa ping
/* Simple ping program */
program
PING_PROG
{
/* Latest and greatest version */
version
PING_VERS_PINGBACK
{
void
PINGPROC_NULL
(void) = 0;
/*
* Ping the caller, return the round-trip time (in microseconds).
Returns -1 if the operation timed out.
*/
int
PINGPROC_PINGBACK
(void) = 1;
} = 2;
/* Original version */
version
PING_VERS_ORIG
{
void
PINGPROC_NULL
(void) = 0;
} = 1;
Identificación de llamadas a RPC
Un mensaje de llamada de
RPC se identifica
unívocamente
mediante tres campos enteros sin signo:
(NUM-PROG, NUM-VERSION, NUM-PROCEDURE)
NUM-PROG es el
número de programa remoto
,
NUM-VERSION es el
número de versión de programa
,
NUM-PROCEDURE es el
número de procedimiento remoto
Detalles de implementación:
NUM-PROG se definen en la RFC 1831
http://www.ietf.org/rfc/rfc1831.txt
La primera implementación (versión) de un protocolo deber ser la
1
El proceso
portmapper
El
enlace
en las RPC de sun se realiza mediante un proceso denominado
portmapper
En
cada servidor
ejecuta un proceso
portmapper
en un
puerto bien conocido
(
111
)
El
portmapper
almacena por
cada servicio local
:
El número de programa
El número de versión
El número de puerto
El número de puerto
Enlace dinámico
:
El número de puertos disponibles es limitado y el número de programas remotos
potenciales puede ser muy grande
Sólo el portmapper ejecutará en un puerto determinado (111) y los números de puertos
donde escuchan los servidores se averiguan preguntando al portmapper
Soporta
TCP
y
UDP
(ver /etc/services)
sunrpc
111/tcp
portmapper
#RPC 4.0
portmapper
El proceso
portmapper
Protocolo:
Cuando un
servidor
arranca
registra en el
portmapper
la información
anterior
Cuando un
cliente
necesita invocar un procedimiento remoto envía al
portmapper
del host remoto (necesita conocer la dirección IP del
servidor)
El número de programa y el número de versión
rpcinfo –p guernika.lab.inf.uc3m.es
./servidor &
El proceso
portmapper
rpcinfo –p guernika.lab.inf.uc3m.es
programa vers proto puerto
100000 2 tcp
111 portmapper
100000 2 udp
111 portmapper
…
100024 1 udp
32772 status
100024 1 tcp
59338 status
Biblioteca de funciones de RPC
La
biblioteca de funciones
de RPC
Sistemas Unix
Servicios de RPC
para construir aplicaciones
En el
cliente
Crear un manejador de cliente
Destruir un manejador de cliente
La biblioteca de funciones
rpc.h
es una biblioteca de funciones para desarrollar
aplicaciones distribuidas
que usan RPC:
#include <rpc/rpc.h>
Múltiples niveles de acceso:
Interfaz simplificado
Interfaz simplificado
Servicios de RPC
Crear un
manejador
para el cliente
CLIENT *
clnt_create
(const char *
host, const u_long prognum,
const u_long versnum, const char *nettype)
Argumentos:
host
nombre del host remoto donde se localiza el programa
remoto
prognum
Número de programa del programa remoto
versnum
Número de versión del programa remoto
nettype
Protocolo de transporte:
Servicios de RPC
Destruir el
manejador
del cliente
void
clnt_destroy
(CLIENT *clnt)
Argumentos:
Servicios de RPC
Indicar el
error
en un fallo de RPC:
void
clnt_perror
(CLIENT *clnt, char *s)
void
clnt_pcreateerror
(CLIENT *clnt, char *s)
Argumentos:
Ejemplo: crear/destruir un manejador
#include <stdio.h>
#include <rpc/rpc.h>
#define
RMTPROGNUM
(u_long)0x3fffffffL
/* Define remote program number and version */
#define
RMTPROGVER
(u_long)0x1
main()
{
CLIENT *client
;
/* client handle */
/* Crear el manejador del cliente */
/* Crear el manejador del cliente */
client =
clnt_create
(“as400.somewhere.ibm.com”, RMTPROGNUM, RMTPROGVER, “TCP”);
if (client == NULL){
clnt_pcreateerror
(client, “Could not create client\n”);
exit(1);
}
// Invocar procedimiento remoto
/* Destruir el manejador del cliente */
Invocar un procedimiento (cliente)
Un procedimiento remoto se invoca:
tipo_resultado
procedimiento
_v
(tipo_arg1 arg1,
tipo_arg2 arg2,
…
tipo_argn argn,
CLIENT *clnt)
donde:
donde:
procedimiento
_v
Nombre del procedimiento a invocar
arg1,arg2,…,argn
Argumentos del procedimiento
clnt
Manejador de un cliente de RPC
Implementar un procedimiento
(servidor)
Para cada procedimiento remoto, el servidor ofrece una
implementación
de procedimiento respetando su prototipo:
tipo_resultado
procedimiento_v
_svc
(tipo_arg1 arg1,
tipo_arg2 arg2,
…
tipo_argn argn,
tipo_argn argn,
struct svc_req *rqstp)
donde:
procedimiento_v
_svc
Nombre del procedimiento a implementar
arg1,arg2,…,argn
Argumentos del procedimiento
rqstp
Estructura que contiene información de la
petición
Compilador de interfaces (rpcgen)
rpcgen
es el compilador de interfaces que genera código
C
para:
Stub del cliente
Stub del servidor
y procedimiento principal del servidor
Procedimientos para el empaquetado y desempaquetado XDR
Fichero de cabecera (.h) con los
tipos y declaración de
Fichero de cabecera (.h) con los
tipos y declaración de
Sintaxis de rpcgen
Compilar usando
rpcgen
rpcgen
infile
rpcgen [-abkCLNTM][-Dname[=value]] [-i size] [-I [-K seconds]] [-Y path] infile
rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm] [-o outfile] [infile]
rpcgen [-s nettype]* [-o outfile] [infile]
rpcgen [-n netid]* [-o outfile] [infile]
infile
fichero en lenguaje de definición de interfaz de RPC
infile
fichero en lenguaje de definición de interfaz de RPC
(XDR en RPC de SUN)
Algunas opciones:
-N
Permite a los procedimientos tener múltiples argumentos
-a
Genera todos los ficheros incluyendo código de ejemplo para
cliente y servidor
Ejemplo: aplicación con RPC
cliente
sumar(5,2)
5+2
servidor
Máquina A
Máquina B
NÚCLEO
Resultado = 7
NÚCLEO
RED
Esquema de la aplicación
rpcgen
suma_xdr.c
suma_clnt.c
cliente.c
Archivos para
el cliente
Archivos
suma.x
rpcgen
suma_svc.c
servidor.c
suma.h
Archivos
comunes
Archivos para
el servidor
struct argumentos {
int a;
int b;
};
program
SUMAR
{
version
SUMAVER
{
Ejemplo: suma.x
version
SUMAVER
{
int SUMA(argumentos) = 1;
int RESTA(argumentos) = 2;
} = 1;
Ejemplo: suma.h
#ifndef _SUMA_H_RPCGEN
#define _SUMA_H_RPCGEN
#include <rpc/rpc.h>
struct argumentos {
int a;
int b;
};
#define SUMAVER ((u_long)99)
#define SUMA ((u_long)1)
#define RESTA ((u_long)2)
extern
int * suma_1(argumentos *, CLIENT *);
extern
int * suma_1_svc(argumentos *, struct svc_req *);
...
Ejemplo: servidor.c
#include "suma.h"
int *suma_1_svc(argumentos *argp, struct svc_req *rqstp)
{
// TODO: implementación del procedimiento suma_1_svc
static int result;
result = argp->a + argp->b;
return(&result);
}
int *resta_1_svc(argumentos *argp, struct svc_req *rqstp)
{
// TODO: implementación del procedimiento resta_1_svc
static int result;
Ejemplo: cliente.c
#include "suma.h"
#include <rpc/rpc.h>
main( int argc, char* argv[] )
{
CLIENT *clnt
;
int
*res;
argumentos suma_1_arg;
argumentos suma_1_arg;
char *host;
if(argc < 2) {
printf("usage: %s server_host\n", argv[0]);
exit(1);
}
Ejemplo: cliente.c (II)
/*
Paso 1: localizar al servidor
*/
clnt =
clnt_create
(host, SUMAR, SUMAVER, "udp");
if (clnt == NULL) {
clnt_pcreateerror
(host);
exit(1);
}
suma_1_arg.a = 5;
suma_1_arg.b = 2;
Binding:
Se contacta con el portmapper de host
Se indica el host:API:versión:protocolo
El portmapper indica la localización
(puerto)
/*
Paso 2: Invocar el procedimiento remoto
*/
res =
suma_1
(&suma_1_arg, clnt);
if (res == NULL) {
clnt_perror
(clnt, "call failed:");
}
printf("La suma es %d\n", *res);
/*
Destruir el manejador
*/
clnt_destroy
( clnt );
suma_xdr.c
#include "suma.h"
bool_t
xdr_argumentos
(XDR *xdrs, argumentos *objp)
{
register int32_t *buf;
if (!
xdr_int
(xdrs, &objp->a))
return FALSE;
if (!
xdr_int
(xdrs, &objp->b))
return FALSE;
return TRUE;
suma_clnt.c (stub del cliente)
#include <memory.h> /* for memset */
#include "suma.h"
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 25, 0 };
int *
suma_1
(argumentos *argp, CLIENT *clnt)
{
static int clnt_res;
Stub Cliente
Servidor Stub
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (
clnt_call
(clnt, suma,
(xdrproc_t) xdr_argumentos, (caddr_t) argp,
(xdrproc_t) xdr_int, (caddr_t) &clnt_res,TIMEOUT) != RPC_SUCCESS)
{
return (NULL);
}
return (&clnt_res);
}
suma_svc.c
(stub del servidor)
int main (int argc, char **argv)
{
register SVCXPRT *transp;
pmap_unset (SUMAR, SUMAVER);
transp =
svcudp_create
(RPC_ANYSOCK);
svc_register
(transp, SUMAR, SUMAVER, sumar_1, IPPROTO_UDP;
transp =
svctcp_create
(RPC_ANYSOCK, 0, 0);
Cliente
Servidor Stub
Stub
transp =
svctcp_create
(RPC_ANYSOCK, 0, 0);
svc_register
(transp, SUMAR, SUMAVER, sumar_1, IPPROTO_TCP;
svc_run
();
fprintf (stderr, "%s", "svc_run returned");
exit (1);
suma_svc.c (II)
(stub del servidor)
static void sumar_1(struct svc_req *rqstp, register SVCXPRT *transp)
{
union {
argumentos suma_1_arg;
argumentos resta_1_arg;
} argument;
char *result;
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, struct svc_req *);
Cliente
Servidor Stub
Stub
char *(*local)(char *, struct svc_req *);
switch (rqstp->rq_proc) {
case NULLPROC:
(void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL);
return;
case suma:
_xdr_argument = (xdrproc_t) xdr_argumentos;
_xdr_result = (xdrproc_t) xdr_int;
suma_svc.c (III)
(stub del servidor)
case resta:
_xdr_argument = (xdrproc_t) xdr_argumentos;
_xdr_result = (xdrproc_t) xdr_int;
local = (char *(*)(char *, struct svc_req *))
resta_1_svc
;
break;
default:
svcerr_noproc (transp); return;
}
memset ((char *)&argument, 0, sizeof (argument));
svc_getargs (transp, _xdr_argument, (caddr_t) &argument);
Cliente
Servidor Stub
Stub
svc_getargs (transp, _xdr_argument, (caddr_t) &argument);
result = (*local)((char *)&argument, rqstp);
if (result != NULL &&
!svc_sendreply(transp, _xdr_result, result)){
svcerr_systemerr (transp);
}
if (!svc_freeargs (transp, _xdr_argument, (caddr_t) &argument)) {
fprintf (stderr, "%s", "unable to free arguments");
exit (1);
}
Compilación
gcc –c suma_xdr.c
gcc –c suma_svc.c
gcc –c suma_clnt.c
gcc –c cliente.c
gcc –c servidor.c
gcc –c servidor.c
gcc
suma_xdr.o suma_clnt.o cliente.o
–o
cliente
Compilación
rpcgen –a –N –M
suma.x
Opciones:
-a: genera todos los ficheros incluyendo ejemplos
-N: permite varios argumentos
-M: genera código
multithread
(código que puede ser utilizado
suma.x:
Ejemplo usando nuevas opciones
program SUMAR {
version SUMAVER {
int suma(int a, int b) = 1;
int resta(int a, int b) = 2;
int resta(int a, int b) = 2;
} = 1;
} = 99;
Nota:
La opción de
compilación –N
permite que un
procedimiento
acepte más de un
argumento de
Ficheros que se generan
suma.h
: incluye prototipos de funciones
suma_client.c
:
ejemplo de cliente.
suma_clnt.c
:
stub
del cliente
suma_server.c
: plantilla con las funciones a implementar
en el servidor
en el servidor
suma_svc.c
:
stub
del servidor
suma.h
#include <rpc/rpc.h>
#include <pthread.h>
struct suma_1_argument {
int a;
int b;
};
};
typedef struct suma_1_argument suma_1_argument;
struct resta_1_argument {
int a;
int b;
};
suma.h (2)
#define SUMAR 99
#define SUMAVER 1
extern enum clnt_stat
suma_1
(int , int , int *, CLIENT
*);
extern bool_t
suma_1_svc
(int , int , int *, struct
svc_req *);
svc_req *);
extern enum clnt_stat
resta_1
(int , int , int *, CLIENT
*);
suma_client.c:
Ejemplo de cliente
#include "suma.h"
void sumar_1(char *host)
{
CLIENT *clnt;
enum clnt_stat retval_1;
int result_1; int suma_1_a; int suma_1_b;
enum clnt_stat retval_2;
enum clnt_stat retval_2;
int result_2; int resta_1_a; int resta_1_b;
clnt =
clnt_create
(host, SUMAR, SUMAVER, “tcp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
retval_1 =
suma_1
(suma_1_a, suma_1_b, &result_1, clnt);
if (retval_1 != RPC_SUCCESS) {
clnt_perror (clnt, "call failed");
}
retval_2 =
resta_1
(resta_1_a, resta_1_b,&result_2, clnt);
if (retval_2 != RPC_SUCCESS) {
suma_client.c:
Ejemplo de cliente (2)
if (retval_2 != RPC_SUCCESS) {
clnt_perror (clnt, "call failed");
}
suma_server:
Plantilla de servidor
#include "suma.h"
bool_t
suma_1_svc(int a, int b, int *result,
struct svc_req *rqstp)
{
bool_t retval;
/*
/*
* insert server code here
*/
*result = a + b;
retval = TRUE;
return retval;
suma_server:
Plantilla de servidor (2)
bool_t resta_1_svc(int a, int b, int *result,
struct svc_req *rqstp)
{
bool_t retval;
/*
* insert server code here
*/
*/
*result = a + b;
retval = TRUE;
return retval;
Autenticación
Los mensajes de petición y respuesta disponen de
campos para pasar información de autenticación
El servidor es el encargado de controlar el acceso
Hay distintos tipos de protocolos de autenticación:
Ninguno
Al estilo UNIX, basado en
uid
y
gid
Autenticación Kerberos
Mediante una clave compartida que se utiliza para firmar los
Sintaxis de definición de un protocolo
definition-list:
definition;
definition; definition-list
definition:
const-definition
enum-definition
struct-definicion
union-definition
typedef-definition
Definición de constantes simbólicas
En XDR
const MAX_SIZE = 8192;
Traducción a C:
Tipos enumerados
En XDR:
enum color{
ROJO = 0;
VERDE = 1;
AZUL = 2;
};
Traducción a C:
Traducción a C:
enum color{
ROJO = 0;
VERDE = 1;
AZUL = 2
};
Estructuras
En XDR:
struct punto{
int x;
int y;
};
Traducción a C:
Traducción a C:
struct punto{
int x;
int y;
};
typdef struct punto punto;
Uniones
En XDR:
union resultado switch (int error){
case 0:
int n;
default:
void;
};
Traducción a C:
Traducción a C:
struct resultado {
int error;
union {
int n;
} resultado_u;
};
typdef struct resultado resultado;
Definición de tipos
En XDR:
typedef punto puntos[2];
Traducción a C:
Pasan sin modificación
Pasan sin modificación
Definición de programas
programa-def:
"program" identifier "{"
version-def
version-def *
"}" "=" contant ";"
version-def:
program SUMAR {
"version" identifier "{"
procedude-def
procedure-def *
"}" "=" constant ";“
procedure-def:
type-ident procedure-ident "("type-ident")" "="
value
program SUMAR {
version SUMAVER {
int suma(int a, int b) = 1;
int resta(int a, int b) = 2;
} = 1;
Tipos de datos básicos
Los tipos de datos básicos de C
Ejemplos:
Enteros con signo:
Declaración:
int a;
Equivalente en C:
int a;
Equivalente en C:
Enteros sin signo:
Declaración:
unsigned a;
Equivalente en C:
unsigned a;
Números en coma flotante:
Declaración:
float a;
Principales tipos de datos en XDR
Números en coma flotante:
Declaración:
float a;
Equivalente en C:
float c;
Cadenas de bytes de longitud fija:
Declaración:
opaque a[20];
Equivalente en C:
char a[20];
Cadenas de bytes de longitud variable:
Declaración:
opaque a<37>;
opaque b<>;
Equivalente en C:
struct {
Principales tipos de datos en XDR
Cadenas de caracteres:
Declaración:
string a<37>;
string b<>;
Equivalente en C:
char *a;
char *b;
char *b;
Vectores de tamaño fijo:
Declaración:
int a[12];
Principales tipos de datos en XDR
Vectores de tamaño variable:
Declaración:
int a<12>;
float b<>;
Equivalente en C:
struct {
int a_len;
int a_len;
int *a_val;
} a;
struct {
int b_len;
Principales tipos de datos en XDR
Estructuras:
Declaración:
struct t {
int c1;
string c2<20>;
};
t a;
Equivalente en C:
struct t {
Equivalente en C:
int c1;
string *c2;
};
typedef struct t t;
t a;
Constantes:
Declaración:
const MAX = 12;
Mensajes de petición-respuesta
Mensaje petición-respuesta
struct rpc_msg {
unsigned int xid;
union switch (msg_type mtype) {
Id. de transacción
union switch (msg_type mtype) {
case CALL:
call_body cbody;
case REPLY:
reply_body rbody;
} body;
};
enum msg_type {
CALL = 0,
REPLY = 1
Formato de los mensajes
MsgType = CALL
XID
RPCVersion = 2
Programa
Versión
0
31
Datos
MsgType = REPLY
XID
Status = ACCEPTED
0
31
Datos
Versión
Procedimiento
Credenciales (variable)
Paradigmas de
procedimientos/métodos remotos
Espacio de objetos, aplicaciones colaborativas
Servicios de red, object request broker, agentes móviles
alto
procedimientos remotos, métodos remotos
Cliente-servidor, peer-to-peer
Paso de mensajes
Llamadas a procedimientos remotos
Objetivo: hacer que el
software distribuido
se
programe igual que una
aplicación no distribuida
Mediante el modelo
RPC
la comunicación se realiza
conceptualmente igual que la invocación de un
procedimiento local
procedimiento local
proc1(arg1, arg2)
proc2(arg1)
proc3(arg1,arg2,arg3)
Llamadas a procedimientos remotos
Pasos:
A
llama al procedimiento remoto de B
La llamada dispara una acción de un procedimiento de B
Al finalizar el procedimiento, B
devuelve el valor a A
Simplifica la comunicación entre procesos y
la sincronización de eventos.
la sincronización de eventos.
Ejemplos:
Open Network Computing Remote Procedure Call
, desarrollada a partir del API
RPC de
Sun Microsystems
a comienzo de los años 80
Llamada a métodos remotos
Primera aproximación al uso de un
modelo orientado a objetos sobre aplicaciones
distribuidas
Objetos distribuidos
dentro de una red
Los
objetos proporcionan métodos
,
los cuales
dan acceso a los servicios
los cuales
dan acceso a los servicios
Ejemplo:
Remote method invocation
(RMI)
Modelo
equivalente
a
las
llamadas a procedimientos remotos
Proceso invoca un método local de otro proceso
Se envían tanto los argumentos del método
como el valor devuelto por el mismo
método1
método2
Proceso 1
Proceso 2
Modelo de objetos en sistemas distribuidos
El soporte para RMI en Java está basado en las interfaces y clases definidas
en los paquetes java.rmi
y java.rmi.server.
RMI ofrece:
Mecanismos para crear servidores y objetos cuyos métodos se puedan
invocar remotamente.
Java RMI (
Remote Method Invocation
)
invocar remotamente.
Mecanismos que permiten a los clientes localizar los objetos remotos.
Servicio de directorios:
Comparación RMI y sockets
Ventajas
:
Los programas RMI son
más sencillos de diseñar
Servidor RMI concurrente
Servidor RMI concurrente
Inconvenientes
:
Arquitectura de RMI
Cliente de
objetos
Servidor
de objetos
Servicio de directorios
stub
Referencia remota
Transporte
skeleton
Referencia remota
Transporte
Arquitectura de RMI
Nivel
de resguardo
o
stub
Se encarga del aplanamiento de los parámetros.
Stub
: resguardo local. Cuando un cliente realiza una invocación remota,
en realidad hace una invocación de un método del resguardo local.
Nivel de
gestión de referencias remotas
stub Referencia remota Transporte skeleton Referencia remota Transporte Cliente de objetos Servidor de objetos Servicio de directorios