Conceptos previos
Un programa es un conjunto de instrucciones.
Un proceso es un programa en ejecución.
Una red de computadores es un conjunto de computadores conectados por una red de interconexión.
Un sistema distribuido (SD)
Modelo físico: conjunto de nodos (procesadores sin memoria ni reloj común) conectados por una red.
Modelo lógico: conjunto de procesos que ejecutan concurrentemente en uno o más computadores que colaboran y comunican intercambiando mensajes.
Un protocolo es un conjunto de reglas e instrucciones que gobiernan la comunicación en un sistema distribuido, es decir, el intercambio de mensajes.
Características
Compartir recursos (HW, SW, datos).
Acceso a recursos remotos.
Modelo cliente–servidor
Modelo basado en objetos
Ofrecen una buena relación coste/rendimiento
Capacidad de crecimiento
Tolerancia a fallos, disponibilidad
Replicación
Concurrencia
Velocidad
Paralelismo
Desventajas
Necesidad de software más complejo
Problemas de fiabilidad
Problemas de seguridad y confidencialidad
Arquitectura de un sistema distribuido
Redes e interconexión
Paquete: tipo de mensaje que se intercambia entre dos dispositivos de comunicación.
Tamaño limitado por el hardware
Mensaje: objeto lógico que se intercambian entre dos o más procesos.
Su tamaño puede ser bastante grande.
Un mensaje se descompone en paquetes.
Subsistema de comunicación: conjunto de componentes HW y SW que proporcionan servicios de comunicación en un sistema distribuido.
Protocolo: conjunto de reglas e instrucciones que gobiernan el intercambio de paquetes y mensajes
Propiedades de un subsistema de comunicación
Tasa de transferencia: velocidad de transferencia
Latencia: tiempo necesario para transferir un mensaje vacío
Tiempo de transferencia = latencia + tamaño/tasa de trasferencia
Paquetes/segundo
Capacidad de crecimiento. Aumento en el nº de nodos
Calidad de servicio
Importante en aplicaciones multimedia y de tiempo real
Fiabilidad del subsistema
Mecanismos de detección de errores
Seguridad: protección de los paquetes
Confidencialidad: proteger la identidad de los emisores
Tipos de redes de computadores
Redes de área local (LAN, Local Area Network)
Redes que enlazan sistemas cercanos
Posibilidad de difusión de mensajes (broadcast)
Redes de área extensa (WAN, Wide Area Network)
Poco ancho de banda (20-500 Kbps)
Bajas latencias
Redes telefónicas, redes públicas de datos, fiabra óptica RDSI, B-RDSI, ATM
Nuevos desarrollos en telecomunicaciones (ATM y RDSI)
Diferencias entre LAN y WAN cada vez más borrosas
Protocolos de comunicación
Protocolo: conjunto de reglas y formatos que permiten la comunicación entre procesos.
La definición de un protocolo tiene dos parte:
Especificación de la secuencia de mensajes que deben intercambiarse.
Especificación del formato de mensajes.
El software de red se organiza en niveles
Funciones de una pila de protocolos
Segmentación y ensamblado de mensajes
Encapsulado: incorporación de información de control a los datos
Dirección del emisor y receptor
Código de detección de errores
Control de conexión
Protocolos orientados a conexión
Protocolos no orientados a conexión:
No se asegura el orden secuencial de los datos transmitidos
Entrega ordenada en protocolos orientados a conexión
Números de secuencia
Funciones de una pila de protocolos II
Control de flujo: función realizada en el receptor para limitar la cantidad o tasa de datos que envía el emisor.
Control de errores: se basan en el uso de una secuencia de comprobación y reenvío.
Direccionamiento, conseguir que los mensajes alcancen al receptor
Multiplexación: necesario para un uso más eficiente de los servicios
Servicios de transmisión:
Prioridad
Calidad de servicio
Seguridad
Ejemplos de protocolos
Protocolos internet:
Originados por el trabajo de DARPA en los 70
Muy utilizados en la actualidad
Gran crecimiento durante los 90 debido al uso del Web
Protocolos OSI (open system interconection)
Estándar desarrollado por ISO
Estándares propietarios
SNA de IBM (años 70)
DECnet desarrollado por DEC
NetWare: red de Novell para redes de PC
Protocolos TCP/IP
Resultado de la investigación y desarrollo llevados a cabo en la red ARPANET (financiada por DARPA) en los años 70
Familia de protocolos utilizados en Internet
En los 90 se ha establecido como la arquitectura comercial dominante:
Se especificaron y utilizaron antes de OSI
Independiente de la tecnología de red utilizada
Internet está construida sobre un conjunto de protocolos TCP/IP.
Espectacular desarrollo de World Wide Web
Protocolos TCP/IP
Protocolo Internet (nivel IP)
La transmisión no es fiable (no se asegura la recepción de los paquetes IP). Los paquetes se pueden descartar por:
Expiración del tiempo de vida
Congestión
Error en la suma de comprobación
Control de flujo muy limitado
Calidad de servicio muy limitado
Seguridad: normal o alto
Retardo: normal o bajo
Rendimiento: normal o alto
Protocolos de transporte
Protocolo TCP
Orientado a conexión
Garantiza que los datos se entregan en el orden en el que se envían
Las conexiones TCP se ven como un flujo de bytes
La transmisión se considera “fiable”. Pueden perderse mensajes (sobrecarga en la red, fallos en encaminadores, etc.)
Cuando los mensajes son muy pequeños, TCP los retrasa hasta conseguir uno más grande
Esta opción debe desactivarse si es necesario
Escrituras concurrentes sobre una misma conexión TCP pueden provocar que los datos se entremezclen.
Protocolos de transporte
Protocolo UDP
Protocolo de datagramas no orientado a conexión.
Protocolo no fiable
Los paquetes se pueden perder, duplicar, recibir en orden distinto al enviado
Tamaño máximo del mensaje: 64 KB
Encaminamiento
Permite que los paquetes viajen del proceso emisor al receptor.
Algoritmo:
Un programa de aplicación genera un paquete, o bien se lee un paquete de la interfaz de red.
Si el paquete es para la máquina, se acepta.
En caso contrario, se incrementa el contador de saltos, si se excede el máximo, el paquete se descarta.
Si el paquete no es para la máquina se busca en la tabla de encaminamiento y se retransmite a la interfaz adecuada.
Tablas estáticas, las más utilizadas
Tablas dinámicas
Papel del sistema operativo
El SW de comunicación de un sistema operativo se organiza como un conjunto de componentes con tareas concretas
Subsistema de almacenamiento: buffers donde almacenar los paquetes que llegan y se envían (limitado)
En implementaciones UNIX típicas
TCP reserva para cada puerto (socket) un buffer de 8 KB y UDP 2 buffers de 8KB. El tamaño se puede incrementar hasta 64 KB.
Los mensajes a enviar se copian a estos buffers
El contenido de estos buffers se fragmenta y se copian a nuevos bloques de memoria a utilizar por IP
IP envía finalmente los paquetes por la interfaz de red correspondiente
Papel del sistema operativo
Un sistema operativo puede perder paquetes cuando la tasa de envíos y de recepción es muy grande.
En sistemas operativos multiusuario la pérdida de paquetes suele producirse a ráfagas debido a los algoritmos de planificación.
La latencia del SO ha crecido en términos relativos
¿Dónde se pierde el tiempo?
Códigos de corrección (Checksum)
Sobre datos TCP y UDP
Sobre cabeceras IP
Copias de datos
Entre usuario y kernel
Estructura de datos
Gestión de los buffers, colas de defragmentación de paquetes IP,
Sistema Operativo
Sobrecarga impuesta por las operaciones del SO
Contenido
Sistemas distribuidos
Sistemas operativos distribuidos
Comunicación de procesos
Sincronización de procesos
Gestión de procesos
Sistemas de archivos
Gestión de memoria
Sistema operativo en red (SOR)
El usuario ve un conjunto de máquinas independientes
No hay transparencia
Se debe acceder de forma explícita a los recursos de otras máquinas
Difíciles de utilizar para desarrollar aplicaciones distribuidas
Sistema operativo distribuido (SOD)
Se comporta como un SO único (visión única)
Distribución. Transparencia
Se construyen normalmente como micronúcleos que ofrecen servicios básicos de comunicación
Mach, Amoeba, Chorus.
Todos los computadores deben ejecutar el mismo SOD
Transparencia
Acceso: acceso a recursos remotos y locales de igual forma
Posición: acceso a los recursos sin necesidad de conocer su situación
Concurrencia: acceso concurrente a recursos compartidos sin interferencias
Replicación: Acceso a recursos replicados sin conocimiento de que lo son
Fallos: mantenimiento del servicio en presencia de fallos.
Migración: permite que los recursos y objetos se muevan sin afectar a la operación de los programas.
Capacidad de crecimiento: facilidad para crecer sin afectar a la estructura del sistema
Middleware y entornos distribuidos
Servicios y protocolos estándarizados: Sistemas abiertos
Ofrecen servicios no incluidos en el SO (servicios de ficheros distribuidos, servicios de nombres, …)
Facilitan el desarrollo de aplicaciones distribuidas
Independientes del HW y del SO subyacente.
DCE, CORBA, DCOM, Legion, Globe, Globus
Servicios de un sistema operativo distribuido
Servicios de comunicación
Servicios de sincronización
Gestión distribuida de procesos
Sistemas de archivos distribuidos
Memoria compartida distribuida
Contenido
Sistemas distribuidos
Sistemas operativos distribuidos
Comunicación de procesos
Sincronización de procesos
Gestión de procesos
Sistemas de archivos
Gestión de memoria
Comunicación en sistemas distribuidos
La comunicación de procesos es fundamental en cualquier sistema distribuido
Existen diferentes posibilidades todas ellas basadas en el paso de mensajes
Mecanismos de bajo nivel, el programador debe preocuparse de establecer los protocolos de comunicación, representación de datos, etc.
Colas de mensajes
Sockets
Mecanismo de alto nivel, ofrecen abstracciones donde el programador no debe preocuparse de establecer protocolos
Llamadas a procedimientos remotos
Invocación de métodos remotos (entornos orientados a objetos)
Comunicación cliente-sevidor
Protocolo típico: petición-respuesta
Muy utilizada en entornos distribuidos (más del 90% de los sistemas distribuidos utilizan la arquitectura cliente-servidor)
Comunicación de grupos
Utiliza mensajes multicast
Útil para:
Ofrecer tolerancia a fallos basado en servicios replicados
Localizar objetos en sistemas distribuidos
Mejor rendimiento mediante datos replicados
Actualizaciones múltiples
Operaciones colectivas en cálculo paralelo
Sockets
Aparecieron en 1981 en UNIX BSD 4.2
Intento de incluir TCP/IP en UNIX
Diseño independiente del protocolo de comunicación
Un socket es punto final de comunicación (dirección IP y puerto)
Abstracción que:
Ofrece interfaz de acceso a los servicios de red en el nivel de transporte
Protocolo TCP
Protocolo UDP
Representa un extremo de una comunicación bidireccional con una dirección asociada
Sockets: introducción
Sujetos a proceso de estandarización dentro de POSIX (POSIX 1003.1g)
Actualmente
Disponibles en casi todos los sistemas UNIX
En prácticamente todos los sistemas operativos
WinSock: API de sockets de Windows
En Java como clase nativa
Sockets UNIX
Dominios de comunicación
Tipos de sockets
Direcciones de sockets
Creación de un socket
Asignación de direcciones
Solicitud de conexión
Preparar para aceptar conexiones
Aceptar una conexión
Transferencia de datos
Dominios de comunicación
Un dominio representa una familia de protocolos
Un socket está asociado a un dominio desde su creación
Sólo se pueden comunicar sockets del mismo dominio
Algunos ejemplos:
PF_UNIX (o PF_LOCAL): comunicación dentro de una máquina
PF_INET: comunicación usando protocolos TCP/IP
Los servicios de sockets son independientes del dominio
Tipos de sockets
Stream (SOCK_STREAM)
Orientado a conexión
Fiable, se asegura el orden de entrega de mensajes
No mantiene separación entre mensajes
Si PF_INET se corresponde con el protocolo TCP
Datagrama (SOCK_DGRAM)
Sin conexión
No fiable, no se asegura el orden en la entrega
Mantiene la separación entre mensajes
Si PF_INET se corresponde con el protocolo UDP
Raw (SOCK_RAW)
Permite el acceso a los protocolos internos como IP
Direcciones de sockets
Cada socket debe tener asignada una dirección única
Las direcciones se usan para:
Asignar una dirección local a un socket (bind)
Especificar una dirección remota (connect o sendto)
Dependientes del dominio
Se utiliza la estructura genérica struct sockaddr
Cada dominio usa una estructura específica
Direcciones en PF_UNIX (struct sockaddr_un)
Nombre de fichero
Direcciones en PF_UNIX (struct sockaddr_in)
Uso de conversión de tipos (casting) en las llamadas
Direcciones de sockets en PF_INET
Host (32 bits) + puerto (16 bits)
Una dirección IP se almacena en una estructura de tipo:
struct in_addr
Estructura struct sockaddr_in
Debe iniciarse a 0
sin_family: dominio (AF_INET)
sin_port: puerto
sin_addr: dirección del host
Función que facilita el nombre de la máquina en la que se ejecuta:
int gethostname(char *name, int namelen);
Obtención de la dirección de host
Usuarios manejan direcciones en forma de texto:
decimal-punto: 138.100.8.100
dominio-punto: laurel.datsi.fi.upm.es
Algunas funciones para trabajar con direcciones:
char *inet_ntoa(struct in_addr in);
Devuelve una dirección en notación decimal-punto.
struct hostent *gethostbyname(char *str);
Convierte una dirección en notación dominio-punto a una estructura que describe máquina.
Algunos campos de la estructura struct hostent:
char *name nombre oficial de la máquina
char **h_addr_list lista de direcciones
Ejemplo
Programa que obtiene la dirección en formato decimal-punto a partir de un formato dominio-punto.
void main(int argc, char **argv) {
struct hostent *hp;
struct in_addr in;
hp = gethostbyname(argv[1]);
if (hp == NULL) {
printf(“Error en gethostbynamen”);
exit(0);
}
memcpy(&in.s_addr,*(hp->h_addr_list),sizeof(in.s_addr));
printf(“%s es %sn”, hp->h_name, inet_ntoa(in));
}
Direcciones de sockets II
En TCP/IP los números se emplean con formato big-endian.
En computadores que no utilicen este formato es necesario emplear funciones para traducir números entre el formato que utiliza TCP/IP y el empleado por el propio computador:
u_long htonl (u_long hostlong)u_short htons (u_short hostshort)u_long ntohl (u_long netlong)u_short ntohs (u_short netshort)
Las primera traduce un número de 32 bits representado en el formato del computador al formato de red (TCP/IP).
Creación de un socket
int socket(int dominio, int tipo, int protocolo)
Crea un socket devolviendo un descriptor de fichero
dominio: PF_XXX
tipo: SOCK_XXX
protocolo: dependiente del dominio y tipo
0 elige el más adeucado
Especificados en /etc/protocols
El socket creado no tiene dirección asignada
Asignación de direcciones
int bind(int sd, struct sockaddr *dir, int long)
sd: descriptor devuelto por socket
dir: dirección a asignar
long: longitud de la dirección
Si no se asigna dirección (típico en clientes)
Se le asigna automáticamente (puerto efímero) en la su primera utilización (connect o sendto)
Direcciones en dominio PF_INET
Puertos en rango 0..65535. Reservados: 0..1023. Si 0, el sistema elige uno
Host: una dirección local IP
INNADDR_ANY: elige cualquiera de la máquina
El espacio de puertos para streams y datagramas es indendiente
Solicitud de conexión
Realizada en el cliente
int connect(int sd, struct sockaddr *dir, int long)
sd: descriptor devuelto por socket
dir: dirección del socket remoto
long: longitud de la dirección
Si el socket no tiene dirección asignada, se le asigna una automáticamente
Normalmente se usa con streams
Preparar para aceptar conexiones
Realizada en el servidor stream después de socket y bind
int listen(int sd, int baklog)
sd: descriptor devuelto por socket
backlog:
Número máximo de peticiones pendientes de aceptar que se encolarán (algunos manuales recomiendan 5)
Hace que el socket quede preparado para aceptar conexiones.
Aceptar una conexión
Realizada en el servidor stream después de socket, bind y listen
Cuando se produce la conexión, el servidor obtiene:
La dirección del socket del cliente
Un nuevo descriptor que queda conectado al socket del cliente
Después de la conexión quedan activos dos sockets en el servidor:
El original para aceptar nuevas conexiones
El nuevo para enviar/recibir datos por la conexión
Aceptar una conexión
int accept(int sd, struct sockaddr *dir, int *long)
sd: descriptor devuelto por socket
dir: dirección del socket del cliente devuelta
long: parámetor valor-resultado
Antes de la llamada: tamaño de dir
Después de la llamada: tamaño de la dirección del cliente que se devuelve.
Obtener la dirección de un socket
Obtener la dirección a partir del descriptor
int getsockname(int sd, struct sockaddr *dir, int *long)
sd: descriptor devuelto por socket
dir: dirección del socket devuelta
long: parámetro valor-resultado (igual que en accept)
Obtener la dirección del socket en el toro extremo de la conexión:
int gerpeername(int sd, struct sockaddr *dir, int *long)
sd: descriptor devuelto por socket
dir: dirección del socket remoto
long: parámetro valor-resultado
Transferencia de datos con streams
Una vez realizada la conexión, ambos extremos puede transferir datos.
Envío:
int write(int sd, char *mem, int long);
Devuelve el nº de bytes enviados
También puede utilizarse el servicio send.
Recepción:
int read(int sd, char *mem, int long);
Devuelve el nº de bytes recibidos
También puede utilizarse el servicio recv
Es importante comprobar siempre el valor que devuelven estas llamadas: pueden no transferirse todos los datos.
Transferencia de datos con streams II
Función que envía un bloque de datos con reintentos:
int enviar(int socket, char *mensaje, int longitud)
{
int r; int l = longitud;
do { r = write(socket, mensaje, l); l = l – r; mensaje = mensaje + r; } while ((l>0) && (r>=0));
if (r < 0) return (-1); /* fallo */ else return(0);
}
Transferencia de datos con datagramas
No hay conexión real
Para usar un socket para transferir basta con:
Crearlo: socket
Asignarle una dirección: bind (si no, lo hará el sistema)
Envío:
int sendto(int sd, char *men, int long, int flags, struct sockaddr *dir, int long)
Devuelve el nº de bytes enviados
dir: dirección del socket remoto y long la longitud
Rccepción:
int recvfrom(int sd, char *men, int long, int flags, struct sockaddr *dir, int long)
Devuelve el nº de bytes enviados
dir: dirección del socket remoto y long la longitud
Cerrar un socket
Se usa close para cerrar ambos tipos de sockets
Si el socket es de tipo stream, close cierra la conexión en ambos sentidos
Se puede cerrar un único extremo:
int shutdown(int st, int modo)
sd: descriptor devuelto por socket
modo: SHUT_RD, SHUT_RW o SHUT_RDWR
Configuración de opciones
Existen varios niveles dependiendo del protocolo afectado como parámetro
SOL_SOCKET: opciones independientes del protocolo
IPPROTO_TCP: nivel de protocolo TCP
IPPTOTO_IP: nivel de protocolo IP
Consultar opciones asociadas a un socket
int getsockopt(int sd, int nivel, int opc, char *val, int *long)
Modificar las opciones asociadas a un socket
int setsockopt(int sd, int nivel, int opc, char *val, int long)
Ejemplos (nivel SOL_SOCKET):
SO_REUSEADDR: permite reutilizar direcciones
Escenario típico con sockets streams
(Gp:) Proceso cliente
(Gp:) Proceso servidor
(Gp:) socket()
(Gp:) socket()
(Gp:) bind()
(Gp:) listen()
(Gp:) accept()
(Gp:) Crear
(Gp:) thread
(Gp:) read()
(Gp:) close()
(Gp:) accept()
(Gp:) connect()
(Gp:) Abrir conexión
(Gp:) read()
(Gp:) close()
(Gp:) Petición
(Gp:) write()
(Gp:) Respuesta
(Gp:) write()
Ejemplo (TCP)
Servidor (TCP)
void main(int argc, char *argv[])
{
struct sockaddr_in server_addr, client_addr;
int sd, sc;
int size, val;
int size;
int num[2], res;
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
val = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(int));
bzero((char *)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = 4200;
bind(sd, &server_addr, sizeof(server_addr));
Servidor (TCP)
listen(sd, 5);
size = sizeof(client_addr);
while (1)
{
printf("esperando conexionn");
sc = accept(sd, (struct sockaddr *)&client_addr,&size);
read(sc, (char *) num, 2 *sizeof(int)); // recibe la petición
res = num[0] + num[1];
write(sc, &res, sizeof(int)); // se envía el resultado
close(sc);
}
close (sd);
exit(0);
}
Cliente (TCP)
void main(void)
{
int sd;
struct sockaddr_in server_addr;
struct hostent *hp;
int num[2], res;
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bzero((char *)&server_addr, sizeof(server_addr));
hp = gethostbyname ("arlo.datsi.fi.upm.es");
memcpy (&(server_addr.sin_addr), hp->h_addr, hp->h_length);
server_addr.sin_family = AF_INET;
server_addr.sin_port = 4200;
Cliente (TCP)
// se establece la conexión
connect(sd, (struct sockaddr *) &server_addr, sizeof(server_addr));
num[0]=5;
num[1]=2;
write(sd, (char *) num, 2 *sizeof(int)); // envía la petición
read(sd, &res, sizeof(int)); // recibe la respuesta
printf("Resultado es %d n", res);
close (sd);
exit(0);
}
Servidor (datagramas)
void main(void)
{
int num[2];
int s, res, clilen;
struct sockaddr_in server_addr, client_addr;
s = socket(AF_INET, SOCK_DGRAM, 0);
bzero((char *)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = 7200;
bind(s, (struct sockaddr *)&server_addr, sizeof(server_addr));
Servidor (datagramas)
clilen = sizeof(client_addr);
while (1)
{
recvfrom(s, (char *) num, 2* sizeof(int), 0,
(struct sockaddr *)&client_addr, &clilen);
res = num[0] + num[1];
sendto(s, (char *)&res, sizeof(int), 0,
(struct sockaddr *)&client_addr, clilen);
}
}
Cliente (datagramas)
void main(int argc, char *argv[]){
struct sockaddr_in server_addr, client_addr;
struct hostent *hp;
int s, num[2], res;
if (argc != 2){
printf("Uso: client < direccion_servidor> n");
exit(0);
}
s = socket(AF_INET, SOCK_DGRAM, 0);
hp = gethostbyname (argv[1]);
bzero((char *)&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
memcpy (&(server_addr.sin_addr), hp->h_addr, hp->h_length);
server_addr.sin_port = 7200;
Cliente (datagramas)
bzero((char *)&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = INADDR_ANY;
client_addr.sin_port = htons(0);
bind (s, (struct sockaddr *)&client_addr, sizeof(client_addr));
num[0] = 2; num[1] = 5;
sendto(s, (char *)num, 2 * sizeof(int), 0,
(struct sockaddr *) &server_addr, sizeof(server_addr));
recvfrom(s, (char *)&res, sizeof(int), 0, NULL, NULL);
printf("2 + 5 = %dn", res);
close(s);
}
Llamadas a procedimientos remotos (RPC)
RPC (remote procedure call): llamadas a procedimiento remoto (Birrel y Nelson 1985)
Híbrido entre llamadas a procedimientos y paso de mensajes
Las RPC constituyen el núcleo de muchos sistemas distribuidos
Llegaron a su culminación con DCE (Distributed Computing Environment)
Han evolucionado hacia orientación a objetos
Invocación de métodos remotos (CORBA, RMI)
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).
Llamadas y mensajes en una RPC
Suplentes (stubs)
Se generan automáticamente por el software de RPC
En el cliente:
Localizan al servidor
Empaquetan los parámetros y construyen los mensajes
Envían el mensaje al servidor
Espera la recepción del mensaje y devuelven los resultados
En el servidor
Realizan tareas similares
Los suplentes son independientes de la implementación que se haga del cliente y del servidor. Sólo dependen de la interfaz.
RPC: protocolo básico
cliente
servidor
Desempaqueta
la respuesta
Se registra con un servicio de nombres
(Gp:) recibe petición
(Gp:) Ejecuta el
procedimiento
(Gp:) envía petición
“enlaza con el servidor”
prepara parámetros, envía petición
Aspectos de diseño de las RPC
Lenguaje de definición de interfaces. Generador de suplentes.
Transferencia de parámetros
Enlace dinámico (binding)
Semántica de las RPC en presencia de fallos
Lenguaje de definición de interfaces
Una interfaz especifica un nombre de servicio que utilizan los clientes y servidores
Nombres de procedimientos y parámetros (entrada y salida).
Los compiladores pueden diseñarse para que los clientes y servidores se escriban en lenguajes diferentes.
Tipos de RPC
Integrado con un lenguaje de programación (Cedar, Argus)
Lenguaje de definición de interfaces específico para describir las interfaces entre los clientes y los servidores (RPC de Sun y RPC de DCE)
Transferencia de parámetros
Una de las funciones de los resguardos 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
Transmisión con un formato estándar:
XDR (external data representation) es un estándar que define la representación de tipos de datos
El receptor se encarga de la conversión (CORBA).
Problemas con los punteros
Una dirección sólo tiene sentido en un espacio de direcciones
Aplanamiento
Enlace dinámico (Binding)
Enlace dinámico: permite localizar objetos con nombre en un sistema distribuido, en concreto, servidores que ejecutan las RPC.
Tipos de enlace:
Enlace no persistente: la conexión entre el cliente y el servidor se establece en cada RPC.
Enlace persistente: la conexión se mantiene después de la primera RPC.
Útil en aplicaciones con muchas RPC repetidas
Problemas si lo servidores cambian de lugar
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
Buscar la dirección correspondiente a un nombre de servicio
Como localizar al enlazador dinámico:
Ejecuta en una dirección fija de un computador fijo.
El sistema operativo se encarga de indicar su dirección
Difundiendo un mensaje (broadcast) cuando los procesos comienzan su ejecución.
Establecimiento de la comunicación en una RPC
Semántica de las RPC en presencia de fallos
Problemas que pueden plantear las RPC
El cliente no es capaz de localizar al servidor
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 cliente falla después de enviar una petición
Cliente no puede localizar al servidor
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
Devolviendo un código de error (-1)
No es transparente
Ejemplo: sumar(a,b)
Elevando una excepción
Necesita un lenguaje que tenga excepciones
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 no se recibe una respuesta se retransmite
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 sin problemas (operaciones idempotentes)
Una transferencia bancaria no es idempotente
Solución con operaciones no idempotentes es descartar peticiones ya ejecutadas
Un nº de secuencia en el cliente
Un campo en el mensaje que indique si es una petición original o una retransmisión
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
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
Sería lo deseable
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 cliente rearranca y ejecuta de nuevo la RPC se pueden crear confusiones
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 un específico
Algunos utilizan TCP o UDP como protocolos básicos
Programación con un paquete de RPC
El programador debe proporcionar:
La definición de la interfaz (idl)
Nombres de las funciones
Parámetros que el cliente pasa al servidor
Resultados que devuelve el servidor al cliente
El código del cliente
El código del servidor
El compilador de idl proporciona:
El resguardo del cliente
El resguardo del servidor
Programación con RPC
(Gp:) COMPILADOR C
(Gp:) COMPILADOR C
(Gp:) COMPILADOR C
(Gp:) COMPILADOR C
(Gp:) CABECERA
(Gp:) CABECERA
(Gp:) FICHEROS
(Gp:) FUENTE DEL
(Gp:) CLIENTE
(Gp:) FICHEROS
(Gp:) OBJETO DEL
(Gp:) CLIENTE
(Gp:) FICHEROS
(Gp:) OBJETO DEL
(Gp:) SERVIDOR
(Gp:) EJECUTABLE
(Gp:) DEL
(Gp:) CLIENTE
(Gp:) EJECUTABLE
(Gp:) DEL
(Gp:) SERVIDOR
(Gp:) FICHEROS
(Gp:) FUENTE DEL
(Gp:) SERVIDOR
(Gp:) OBJETO
(Gp:) SUPLENTE
(Gp:) EN CLIENTE
(Gp:) OBJETO
(Gp:) SUPLENTE
(Gp:) EN SERVIDOR
(Gp:) MONTADOR
(Gp:) MONTADOR
(Gp:) BIBLIOT.
(Gp:) RPC
(Gp:) BIBLIOT.
(Gp:) RPC
(Gp:) DESARROLLO
(Gp:) DE LA
(Gp:) INTERFAZ
(Gp:) DESARROLLO
(Gp:) DEL
(Gp:) CLIENTE
(Gp:) DESARROLLO
(Gp:) DEL
(Gp:) SERVIDOR
(Gp:) COMPILADOR IDL
(Gp:) SUPLENTE
(Gp:) EN SERVIDOR
(Gp:) SUPLENTE
(Gp:) EN CLIENTE
(Gp:) CABECERA
FICHERO
DE DEFINICIÓN
DE INTERFAZ
Ejemplos de paquetes de RPC
RPC de Sun (1990) utilizado en NFS
RPC del proyecto ANSA (1989) desarrollado por Architecture Project Management Ltd. (Cambridge, Inglaterra)
RPC de DCE (1990), estándar desarrollado por Open Software Foundation
RPC de Sun
Utiliza como lenguaje de definición de interfaz XDR:
Una interfaz contiene un nº de programa y un nº de versión.
Cada procedimiento específica un nombre y un nº de procedimiento
Los procedimientos sólo aceptan un parámetro.
Los parámetros de salida se devuelven mediante un único resultado
El lenguaje ofrece una notación para definir:
constantes
definición de tipos
estructuras, uniones
programas
RPC de Sun
rpcgen es el compilador de interfaces que genera:
Suplente del cliente
Suplente del servidor y procedimiento principal del servidor.
Procedimientos para el aplanamiento (marshalling)
Fichero de cabecera (.h) con los tipos y declaración de prototipos.
Enlace dinámico
El cliente debe especificar el host donde ejecuta el servidor
El servidor se registra (nº de programa, nº de versión y nº de puerto) en el portmapper local
El cliente envía una petición al portmapper del host donde ejecuta el servidor
Ejemplo
Esquema de la aplicación
suma.x
struct peticion {
int a;
int b;
};
program SUMAR {
version SUMAVER {
int SUMA(peticion) = 1;
} = 1;
} = 99;
suma.h
#ifndef _SUMA_H_RPCGEN
#define _SUMA_H_RPCGEN
#include < rpc/rpc.h>
struct peticion {
int a;
int b;
};
#define SUMAVER ((u_long)99)
#define SUMA ((u_long)1)
extern int * suma_1(peticion *, CLIENT *);
extern int * suma_1_svc(peticion *, struct svc_req *);
#endif /* !_SUMA_H_RPCGEN */
servidor.c
#include "suma.h"
int *suma_1_svc(peticion *argp, struct svc_req *rqstp)
{
static int result;
result = argp->a + argp->b;
return(&result);
}
cliente.c
#include "suma.h"
main( int argc, char* argv[] )
{
CLIENT *clnt;
int *res;
peticion suma_1_arg;
char *host;
if(argc < 2) {
printf("usage: %s server_hostn", argv[0]);
exit(1);
}
host = argv[1];
cliente.c II
/* localiza 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;
res = suma_1(&suma_1_arg, clnt);
if (res == NULL) {
clnt_perror(clnt, "call failed:");
}
printf("La suma es %dn", *res);
clnt_destroy( clnt );
}
Contenido
Sistemas distribuidos
Sistemas operativos distribuidos
Comunicación de procesos
Sincronización de procesos
Gestión de procesos
Sistemas de archivos
Gestión de memoria
Relojes lógicos
En ausencia de un reloj global la relación causa-efecto (precede a) es la única posibilidad de ordenar eventos
Relación de precedencia (Lamport)
Si a y b son dos eventos del mismo proceso y a ocurrió antes que b, entonces a Y b
Si a=send(m) y b=receive(m), entonces a Y b
La relación es transitiva
Dos eventos son concurrentes (a || b) si no se puede deducir entre ellos una relación de causalidad potencial
Relojes lógicos (algoritmo de Lamport)
Útiles para ordenar eventos en ausencia de un reloj común.
Algoritmo de Lamport (1978)
Cada proceso P mantiene una variable entera RLp (reloj lógico)
Cuando un proceso P genera un evento, RLp=RLp+1
Cuando un proceso envía un mensaje m a otro le añade el valor de su reloj
Cuando un proceso Q recibe un mensaje m con un valor de tiempo t, el proceso actualiza su reloj, RLq=max(RLq,t)
El algoritmo asegura que si a Y b entonces RL(a) < RL(b)
Página siguiente |