aplicaciones distribuidas resumen apuntrix

99
Aplicaciones Distribuidas Curso 2014/15 Resumen de la asignatura para apuntrix.com

Upload: jose-maria-gonzalez-rios

Post on 06-Dec-2015

101 views

Category:

Documents


8 download

DESCRIPTION

java;rmi

TRANSCRIPT

Page 1: Aplicaciones Distribuidas Resumen Apuntrix

Aplicaciones Distribuidas

Curso 2014/15

Resumen de la asignaturapara apuntrix.com

Page 2: Aplicaciones Distribuidas Resumen Apuntrix

Índice

1. Introducción a la computación distribuida 11.1. Definiciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2. La historia de la computación distribuida . . . . . . . . . . . . . . . . . . . . . . . . 1

1.3. Diferentes formas de computación . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.4. Virtudes y limitaciones de la computación distribuida . . . . . . . . . . . . . . . . 2

1.5. Conceptos básicos de sistemas operativos . . . . . . . . . . . . . . . . . . . . . . . . 2

1.6. Conceptos básicos de redes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.7. Conceptos básicos de ingeniería del software . . . . . . . . . . . . . . . . . . . . . . 8

2. IPC - Comunicación entre procesos 112.1. Un arquetipo de interfaz de programación para comunicación entre procesos . . . 11

2.2. Sincronización de eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.3. Temporizadores e hilos de ejecución . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.4. Interbloqueos y temporizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.5. Representación de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.6. Codificación de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.7. Protocolos basados en texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.8. Protocolos de solicitud-respuesta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.9. Diagrama de eventos y diagrama de secuencia . . . . . . . . . . . . . . . . . . . . . 13

2.10. Comunicación entre procesos orientada y no orientada a conexión . . . . . . . . . 14

2.11. Evolución de los paradigmas de comunicación entre procesos. . . . . . . . . . . . . 14

3. Paradigmas de computación distribuida 163.1. Paradigmas y abstracción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.2. Una aplicación de ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.3. Paradigmas para aplicaciones distribuidas . . . . . . . . . . . . . . . . . . . . . . . 16

3.4. Comparativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

4. El API de sockets 234.1. Antecedentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.2. La metáfora del socket en IPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.3. El API de sockets datagrama . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.4. El API de sockets en modo stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

4.5. Sockets con operaciones de E/S no bloqueantes . . . . . . . . . . . . . . . . . . . . . 34

4.6. El API de sockets seguros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

5. El paradigma cliente-servidor 365.1. Antecedentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

5.2. Cuestiones sobre el paradigma cliente-servidor . . . . . . . . . . . . . . . . . . . . 36

5.3. Ingeniería de software de un servicio de red . . . . . . . . . . . . . . . . . . . . . . 37

5.4. Servidores orientados a conexión y sin conexión . . . . . . . . . . . . . . . . . . . . 43

5.5. Servidor iterativo y servidor concurrente . . . . . . . . . . . . . . . . . . . . . . . . 47

5.6. Servidores con estado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

7. Objetos distribuidos 527.1. Paso de mensajes frente a objetos distribuidos . . . . . . . . . . . . . . . . . . . . . 52

7.2. Una arquitectura típica de objetos distribuidos . . . . . . . . . . . . . . . . . . . . . 52

7.3. Sistemas de objetos distribuidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

7.4. Llamadas a procedimientos remotos . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

7.5. RMI (Remote Method Invocation) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

7.6. La arquitectura de Java RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

7.7. API de Java RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

7.8. Una aplicación RMI de ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

7.9. Pasos para construir una aplicación RMI . . . . . . . . . . . . . . . . . . . . . . . . 60

7.10. Pruebas y depuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

7.11. Comparación entre RMI y el API de sockets . . . . . . . . . . . . . . . . . . . . . . . 61

Page 3: Aplicaciones Distribuidas Resumen Apuntrix

8. RMI avanzado 628.1. Callback de cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

8.2. Descarga de resguardo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

8.3. El gestor de seguridad de RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

10. CORBA - Common Object Request Broker Architecture 7210.1. Arquitectura básica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

10.2. La interfaz de objetos de CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

10.3. Protocolos inter-ORB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

10.4. Servidores de objetos y clientes de objetos . . . . . . . . . . . . . . . . . . . . . . . 73

10.5. Referencias a objetos CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73

10.6. Servicio de nombres y servicio de nombres interoperable en CORBA . . . . . . . . 73

10.7. Servicios de objetos CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

10.8. Adaptadores de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

10.9. IDL de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

11. Servicios web/Aplicaciones de Internet 8311.1. ¿Qué es un servicio web? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

11.2. Funcionalidad de transporte de WSA: SOAP. . . . . . . . . . . . . . . . . . . . . . . 84

11.3. Funcionalidad de descripción de WSA: WSDL . . . . . . . . . . . . . . . . . . . . . 85

11.4. Funcionalidad de descubrimiento de WSA: UDDI . . . . . . . . . . . . . . . . . . . 88

11.5. Implementación de la arquitectura WSA . . . . . . . . . . . . . . . . . . . . . . . . 89

11.6. Servicios web [11.3. de Computación Distribuida, M. L. Liu] . . . . . . . . . . . . . 90

11.7. SOAP [11.4. de Computación Distribuida, M. L. Liu] . . . . . . . . . . . . . . . . . 91

Page 4: Aplicaciones Distribuidas Resumen Apuntrix

1. Introducción a la computación distribuida

1.1. Definiciones

Un monoprocesador o la computación monolítica utiliza una única unidad central de pro-ceso o CPU para ejecutar uno o más programas por cada aplicación.

Un sistema distribuido es un conjunto de computadores independientes, interconectados através de una red y que son capaces de colaborar con el fin de realizar una tarea. Los compu-tadores se consideran independientes cuando no comparten memoria ni espacio de ejecuciónde los programas. Dichos computadores se denominan computadores ligeramente acoplados,frente a los computadores fuertemente acoplados, que pueden compartir datos a través de unespacio de memoria común.

La computación distribuida es computación que se lleva a cabo en un sistema distribuido.

Un servicio de red es un servicio proporcionado por un tipo de programa especial deno-minado servidor en una red.

Una aplicación de red es una aplicación para usuarios finales, que se ejecuta en compu-tadores conectados a través de una red.

La diferencia entre servicios y aplicaciones de red no es siempre nítida y estos términos frecuen-temente se intercambian.

1.2. La historia de la computación distribuida

La conexión de computadores aislados de forma que los datos se pudieran intercambiarfue una progresión natural. El primer RFC (Request For Comments) de Internet, RFC 1, es unapropuesta que especifica cómo las máquinas participantes pueden intercambiar información conotras a través del uso de mensajes. Hasta el día de hoy, el correo electrónico y la transferencia deficheros siguen siendo dos de los más populares servicios de red. Sin embargo, el más conocidoes indudablemente la World Wide web.

1.3. Diferentes formas de computación

Para comprender qué significa la computación distribuida, resulta instructivo analizar dife-rentes formas de computación.

Computación monolítica

En la forma más sencilla de computación, un único computador se utiliza para la compu-tación. Dicho computador sólo puede utilizar aquellos recursos a los que tiene acceso de manerainmediata. Esta forma se denomina computación monolítica. En su forma más básica se de-nomina computación monolítica monousuario, donde un único usuario utiliza el computador a lavez.

La computación monolítica permite la convivencia de múltiples usuarios, que pueden com-partir de forma concurrente los recursos de un único computador a través de una técnica deno-minada tiempo compartido. El computador que proporciona el recurso centralizado se denomi-na mainframe. Los usuarios, que podrían estar dispersos geográficamente, se pueden conectar almainframe durante una sesión a través de dispositivos denominados terminales.

Computación distribuida

La computación distribuida implica el uso de múltiples computadores conectados a la red,cada uno de los cuales tiene su propio procesador o procesadores y otros recursos. Un usuarioque utilice una estación de trabajo puede usar los recursos del computador local. A través dela interacción entre el computador local y los computadores remotos, el usuario también puedeacceder a los recursos de estos últimos. La web es un ejemplo de este tipo de computación. Eluso de un navegador para visitar un sitio web implica la ejecución de un programa en un sistemalocal que interactúa con otro programa que se ejecuta en un sistema remoto.

1

Page 5: Aplicaciones Distribuidas Resumen Apuntrix

Computación paralela

La denominada computación paralela utiliza más de un procesador simultáneamente paraejecutar un único programa. Suele ser difícil dividir un programa de forma que CPU separadasejecuten diferentes porciones del programa sin ninguna interacción.

Hoy en día, la computación paralela se utiliza principalmente en computación científica agran escala.

Computación cooperativa

El término computación distribuida se ha aplicado también a proyectos de computación coope-rativa tales como el de la búsqueda de inteligencia extraterrestre (SETI). Estos proyectos dividenla computación a gran escala entre las estaciones de trabajo de las máquinas de Internet, utili-zando ciclos de CPU excedentes.

1.4. Virtudes y limitaciones de la computación distribuida

Diferentes razones para la popularidad de la computación distribuida:

Los computadores y el acceso a la red son económicos. Los computadores personalesactuales tienen una potencia superior a los primeros mainframes, además de tener muchomenor tamaño y precio. Además, la conexión a Internet está disponible universalmente yes económica.

Compartición de recursos. La arquitectura de la computación distribuida refleja la arqui-tectura de computación de las organizaciones modernas. Mediante ella, las organizacionespueden utilizar sus recursos de forma efectiva.

Escalabilidad. En la computación monolítica, los recursos disponibles están limitados porla capacidad de un computador. La computación distribuida proporciona escalabilidad,debido a que permite incrementar el número de recursos compartidos según la demanda.

Tolerancia a fallos. La computación distribuida permite que un recurso pueda ser re-plicado con el fin de dotar al sistema tolerancia a fallos. El desarrollador que diseña eimplementa un sistema es el responsable de maximizar la tolerancia a fallos del mismo.

La computación distribuida también tiene algunas desventajas:

Múltiples puntos de fallo. Hay más puntos de fallo en la computación distribuida. Debidoa que múltiples computadores están implicados en la computación distribuida, y todos sondependientes de la red para su comunicación.

Aspectos de seguridad. En un sistema distribuido hay más oportunidades de ataques noautorizados. La gestión es descentralizada y frecuentemente implica a un gran númerode organizaciones independientes. La descentralización hace difícil implementar y ejecutarpolíticas de seguridad.

1.5. Conceptos básicos de sistemas operativos

A continuación se describen algunos de los conceptos implicados en la ejecución de progra-mas en computadores actuales.

Programas y procesos de computación

Un programa software es un artefacto construido por un desarrollador software utilizandoalguna forma de lenguaje de programación. Cuando un programa se ejecuta en un computadorse representa como un proceso. Un proceso consiste en un programa que se ejecuta, sus valo-res actuales, la información de estado y los recursos utilizados por el sistema operativo paragestionar su ejecución.

Hay tres tipos de programas Java: aplicaciones (Listado 1), applets (Listado 2) y servlets(Listado 3). Cada programa se escribe como una clase Java. Una aplicación Java tiene un métodoprincipal (main) y se ejecuta como un proceso independiente (standalone).

2

Page 6: Aplicaciones Distribuidas Resumen Apuntrix

Un applet no tiene un método main y se ejecuta mediante el uso de un navegador o de laherramienta que permite ver applets, appletviewer. un servlet es parecido al applet en el hechode que no tiene un método main. Se ejecuta en el contecto de un servidor web.

Un programa Java se compila y se convierte a un código denominado bytecode. Cuando seejecuta, la Máquina Virtual Java (JVM) traduce el bytecode a código máquina nativo del compu-tador. Debido a que el bytecode es un código intermedio independiente del tipo de máquina, sedice que los programas Java son independientes de la plataforma.

import java.io.*;

class MiPrograma {public static void main(String[] args) throws IOException {

BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in));String nombre;System.out.println("¿Cuál es tu nombre?");nombre = teclado.readLine();System.out.print("Hola " + nombre);System.out.println(" - Bienvenido a CSC369.\n");

}}

Listado 1: Una aplicación stand-alone Java y el código correspondiente.

import java.applet.Applet;import java.awt.*;

public class MiApplet extends Applet {public void paint(Graphics g) {

setBackground(Color.blue);Font Claude = new Font("Arial", Font.BOLD, 40);g.setFont(Claude);g.setColor(Color.yellow);g.drawString("Hola Mundo", 100, 100);

}}

<title>Un applet sencillo</title><hr><applet code="MiApplet.class" width="500" height="500"></applet>

3

Page 7: Aplicaciones Distribuidas Resumen Apuntrix

<hr><a href="HolaMundo.java">El fichero fuente.</a>

Listado 2: Un applet (arriba) y la página web (abajo) que permite activarlo.

import java.io.*;import java.text.*;import java.util.*;import javax.servlet.*

public class MiServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response) throws

ServletException, IOException {PrintWriter salida;String titulo = "Salida de MiServlet";

//primero establecer el tipo de contenido y otros campos de la cabeceraresponse.setContentType("text/html");//a continuación escribir los datos de la respuestasalida = response.getWriter();salida.println("<HTML><HEAD><TITLE>");salida.println(titulo);salida.println("</TITLE></HEAD><BODY>");salida.println("<H1>" + titulo + "</H1>");salida.println("<p>Hola Mundo</p>");salida.println("</BODY></HTML>");salida.close();

}}

Listado 3: Un servlet (arriba) y la página web (abajo) qie permite activarlo.

Programación concurrente

La programación concurrente consiste en la ejecución simultánea de procesos, y existen tresclases:

Procesos concurrentes ejecutados en múltiples computadores. Procesos separados ejecu-tando concurrentemente en computadores independientes interconectados a través de unared. Los procesos interactúan con otros procesos mediante el intercambio de datos sobre lared, pero su ejecución es por otra parte completamente independiente.

Procesos concurrentes ejecutados en un único computador. La concurrencia puede serreal o virtual. La verdadera concurrencia multitarea sólo es posible si el computador tienemúltiples CPU. En un computador con una sola CPU, se utiliza tiempo compartido pa-ra permitir que los procesos puedan ejecutarse por turnos, creando la ilusión de que seejecutan en paralelo.

Programación concurrente dentro de un proceso. Muchas veces un único programa nece-sita iniciar diferentes tareas que se ejecuten concurrentemente. Por ejemplo, un programapodrá necesitar realizar otras tareas mientras espera indefinidamente por la entrada de unusuario en una interfaz de ventanas.

4

Page 8: Aplicaciones Distribuidas Resumen Apuntrix

Procesos padres e hijosEn tiempo de ejecución, un proceso puede crear procesos hijos. El proceso original, denominadoproceso padre, continúa ejecutándose simultáneamente con el proceso hijo. Un proceso hijo esun proceso completo, y un proceso padre puede saber cuándo uno de sus procesos hijos hafinalizado.

Threads o hilosEn lugar de procesos hijos, un proceso puede crear threads o hilos, también conocidos comoprocesos ligeros. Los hilos poseen un mínimo de información de estado, comportándose por lodemás de la misma forma que los procesos, pero implican menos sobrecarga.

La ejecución concurrente de los hilos puede ocasionar una condición de carrera, que ocurrecuando una serie de mandatos de un programa se ejecutan de una forma arbitraria e intercalada,pudiendo llevarse a cabo una ejecución no determinista.

Las condiciones de carrera se pueden evitar si se utiliza exclusión mutua dentro de unsegmento de código, denominado región crítica.

Hilos JavaLa máquina virtual Java permite que una aplicación tenga múltiples hilos ejecutando concu-rrentemente. Se pueden crear otros hilos adicionales a partir de un hilo activo, y cada hilo seejecutará independientemente y en paralelo con el resto hasta que termine.

Para permitir el uso de hilos en un programa, Java proporciona una clase denominada thready una interfaz denominada runnable. En Java hay dos formas de crear un nuevo hilo de ejecución:

1. Declarar una clase como subclase de la clase thread. Esta subclase debe sobrescribir el elmétodo run de la clase thread.

2. Declarar una clase que implemente la interfaz runnable. Esta clase implementa el métodorun de dicha interfaz.

La manera más sencilla de evitar las condiciones de carrera en Java es a través de la utilización delos métodos estáticos sincronizados. Un método estático que contenga en su cabecera la palabrareservada synchronized puede ejecutarse por un único hilo simultáneamente.

1.6. Conceptos básicos de redes

Protocolos

Un protocolo es un conjunto de reglas que los participantes deben seguir. Los protocolosdeben estar definidos formalmente e implementados de una manera precisa. Debe existir unconjunto de reglas que especifiquen las siguientes cuestiones:

¿Cómo se codifican los datos intercambiados?

¿Cómo los eventos (envío, recepción) se sincronizan (ordenan) de modo que los partici-pantes puedan enviar y recibir información de una forma coordinada?

Por ejemplo, el protocolo HTTP especifica las reglas que deben seguir un proceso del navegadorweb y un proceso del servidor web. Es importante entender que un protocolo es distinto de suimplementación.

Arquitecturas de red

La arquitectura de red clásica se denomina arquitectura OSI y divide las funciones comple-jas de una red en siete capas. Todas o parte de estas funciones deben estar presentes en uncomputador que participa en la comunicación de datos.

La arquitectura de red de Internet está representada en la Figura 1, y está formada porcuatro capas: física, Internet, transporte y aplicación. La capa física proporciona las funcionesde transmisión de señales. La capa Internet permite dirigir y entregar un paquete de datos a uncomputador remoto. La capa de transporte proporciona las funciones necesarias para la entregade paquetes de datos a un proceso específico. Finalmente, la capa de aplicación permite que losmensajes se puedan intercambiar entre los programas.

5

Page 9: Aplicaciones Distribuidas Resumen Apuntrix

Figura 1: La arquitectura de red de Internet

Una arquitectura de capas hace posible que los programas se escriban como si los datos seintercambiaran directamente (véase las líneas disjuntas de la Figura 1).

Protocolos de la arquitectura de red

El protocolo para la capa de Internet se denomina Protocolo de Internet (IP), y utiliza unesquema de nombrado particular para identificar los computadores en una red y para encami-nar los datos. En la capa de transporte, hay dos protocolos ampliamente utilizados: TCP paraproporcionar una comunicación orientada a conexión, y UDP que ofrece una comunicación sinconexión. En la capa de aplicación, existen diferentes protocolos especificados para aplicacionesde red, tales como FTP, SNMP y HTTP. El conocido protocolo TCP/IP es un conjunto de proto-colos que incluye a los protocolos de Internet y transporte de esta arquitectura. Una aplicaciónde Internet debe ejecutarse en un computador que implemente esta parte de la arquitectura deInternet, denominada pila de protocolos TCP/IP.

Comunicación orientada a conexión frente a comunicación sin conexión

En una comunicación orientada a conexión, una conexión, que puede ser física o lógica, seestablece entre dos partes, el emisor y el receptor. Una vez establecida la conexión, los datospueden enviarse continuamente a través de la conexión hasta que la sesión finaliza. En estemodo de comunicación no es necesario especificar explícitamente la dirección del destinatariopara cada paquete de datos individual durante el tiempo que la conexión se utilice.

La comunicación sin conexión implica que no existe conexión. En su lugar, los datos se envíanmediante el uso de paquetes y cada emisor debe indicar de forma explícita en cada paquete ladirección del receptor.

En una red de datos es más sencillo proporcionar una comunicación sin conexión. Sin em-bargo, la falta de conexión puede implicar la pérdida de paquetes de datos en la entrega o laentrega fuera de orden de los mismos.

Por otro lado, la comunicación orientada a conexión puede asegurar la entrega segura yordenada a través de una conexión establecida, pero con el coste adicional de la sobrecarga queimplica este proceso.

Recursos de red

Por recursos de red se entiende aquellos recursos que están disponibles para los participantesde una comunidad de computación distribuida. Por ejemplo, en Internet los recursos de redincluyen hardware tal como los computadores o equipamiento, y software. Una clase importantede recursos de red son los servicios de red, tales como la web o el servicio de transferencia deficheros, que son implementados por procesos que se ejecutan en computadores.

Uno de los retos claves en la computación distribuida es la identificación única de los recursosdisponibles en la red.

Identificación de nodos y direcciones del protocolo de Internet

Físicamente, Internet es una gigantesca malla de enlaces de red y computadores o nodos.Conceptualmente, las principales arterias de Internet son un conjunto de enlaces de red dealto ancho de banda que constituyen el esqueleto central o backbone de la red. Conectadas a este

6

Page 10: Aplicaciones Distribuidas Resumen Apuntrix

backbone existen redes individuales. Los computadores con soporte TCP/IP, denominados nodoso máquinas de Internet, están unidos a redes individuales.

A continuación se analiza el esquema de identificación de nodos especificado en la versión 4

de IP, conocida como IPv4. En IPv4, cada máquina de Internet se identifica por una única cadenade 32 bits. Cada dirección IP debe identificar tanto la red en la cual la máquina reside como lamáquina en sí.

La mayoría de los usuarios tienen problemas para memorizar una cadena de 32 bits, portanto es preferible utilizar un nombre simbólico para identificar un computador. Esta es la razónpor la que la comunidad de Internet adoptó el sistema de nombrado de dominio (DNS). Cadavez que se utiliza el correo electrónico o se visualiza una página web, se identifica la máquinade Internet utilizando un nombre de dominio basado en el protocolo DNS.

Cada nombre de dominio corresponde a una dirección IP, aunque esta asociación no tiene porqué ser permanente. La resolución de un nombre de dominio para obtener la correspondientedirección IP y viceversa se lleva a cabo a través de un servicio conocido como resolución denombres DNS.

Identificación de procesos a través de puertos

En las aplicaciones de red, los datos deben entregarse a un proceso específico que se ejecutaen un computador. Por tanto, se necesita un esquema de nombrado que permita identificarde forma única un proceso. Hay muchos esquemas que permiten realizar esto. Por ejemplo, unaposibilidad es utilizar un único identificador de proceso (PID), que le asigna el sistema operativoal proceso. En Internet, el protocolo utilizado para identificar un proceso usa una entidad lógicaconocida como puerto de protocolo o simplemente puerto. Un proceso que desee intercambiardatos con otro proceso utilizando TCP o UDP debe tener asignado uno de estos puertos. Unaaplicación que desee enviar datos a un proceso actualmente asociado al puerto p en la máquinaM, debe dirigir los datos a (M, p).

En los protocolos TCP y UDP, los números entre el 0 y el 1023 están reservados para serviciosconocidos. Estos puertos se denominan puertos bien conocidos (well-known).

Direcciones de correo electrónico

Una dirección de correo electrónico utiliza el formato nombreUsuario@nombreDominio. Cuan-do se envía un correo electrónico, un programa de correo electrónico en el computador corres-pondiente al nombre de dominio especificado entrega el correo al buzón del usuario especificadoen este sistema.

URL

Cuando se introduce una cadena, tal como http://www.google.es en el navegador webpara visitar un determinado sitio web, se está utilizando un URL.

Un URL es un esquema de nombrado que se encuentra debajo de un esquema más generaldenominado URI. Los URI son cadenas cortas que identifican recursos en la web, incluyendodocumentos, imágenes, ficheros, etc. El esquema URI permite identificar de una forma uniformeestos recursos.

URL es un término informal asociado con populares esquemas URI para protocolos talescomo HTTP , FTP o correo electrónico.

URN es un esquema especificado por el RFC2141 y otros documentos relacionados, que per-mite el uso de identificadores de recursos persistentes e independientes de su localización. UnURN proporciona nombres persistentes e independientes de su localización. Un URN propor-ciona nombres persistentes dentro de un espacio de nombres, permitiendo de esta forma que unobjeto permanente tenga varias copias en varios sitios conocidos.

En su forma más literal, el formato de un URL es:<protocolo>//<usuario>:<clave>@<id-máquina>:<puerto>/<ruta>donde:

<protocolo> es el nombre no sensible a mayúsculas o minúsculas del protocolo de la capade aplicación utilizado para acceder al recurso; por ejemplo, HTTP.

<usuario>:<clave> es la autorización de acceso, en el caso de que sea requerida.

7

Page 11: Aplicaciones Distribuidas Resumen Apuntrix

<id-máquina> es el nombre de dominio o dirección IP decimal.

<puerto> es el puerto para el protocolo de la capa de transporte del proceso que propor-ciona el servicio en la máquina remota.

<ruta> especifica la ruta dentro del sistema de ficheros de la máquina remota donde seencuentra el recurso.

Servicio de nombres extensible

El servicio de nombres extensible (XNS) es un servicio de nombres de Internet gestionadopor la Organización XNS Public Trust Organization, una organización independiente. Permiteun esquema de nombrado con una dirección única y universal para llevar a cabo “todos lostipos de comunicaciones: teléfono, fax, web...”. XNS está diseñado para resolver una direcciónuniversal en cualquier otro tipo de direcciones de cualquier tipo de red de comunicaciones. UnXNS es una cadena de caracteres: nombres personales, nombres de negocio y nombres generales,cada uno de los cuales empieza por un único carácter (=, @ y +, respectivamente).

Resolución de nombres

Siempre que se utiliza un nombre simbólico para identificar un recurso, el nombre debetraducirse a la correspondiente dirección física. Al proceso de traducción se le conoce comoresolución de nombres, o simplemente búsqueda de nombres.

Se debe utilizar una base de datos que contenga las asociaciones entre nombres simbólicos ynombres físicos. Los servidores DNS se encargan de realizar el servicio de búsqueda de nom-bres. Una autoridad central mantiene la base de datos de nombres y permite que la base dedatos se distribuya a través de Internet a los servidores DNS.

1.7. Conceptos básicos de ingeniería del software

La ingeniería del software es la disciplina de informática que aborda el proceso de desarrollode las aplicaciones. Algunos de sus conceptos básicos son relevantes, y los introduciremos acontinuación.

Programación procedimental frente a programación orientada a objetos

Hay dos clases de lenguajes de programación: lenguaje procedimental y lenguaje orientadoa objetos.

Los lenguajes procedimentales (C), utilizan procedimientos para reducir la complejidad delas tareas de la aplicación. Una aplicación puede implementarse utilizando un procedimientoque lleve a cabo la entrada, otro para realizar la computación, y un tercero que genere la salida.

Los lenguajes orientados a objetos (Java, C++) utilizan objetos para encapsular los detalles.Cada objeto simula un objeto de la vida real, almacenando tanto los datos de estado comolos diferentes comportamientos del mismo. Los comportamientos se representan mediante losmétodos.

UML

Un paso importante en la ingeniería del software es la producción de artefactos, o documen-tos, para realizar el diseño conceptual de la aplicación que se está desarrollando. El lenguaje demodelado unificado (UML) proporciona un conjunto de común de lenguaje y notaciones “paraespecificar, visualizar, construir y documentar los artefactos de los sistemas software”.

En este resumen se utilizará ocasionalmente una de estas notaciones: los diagramas de claseUML, para documentar las relaciones de algunas de las clases Java que aparecen en la presenta-ción. La Figura 2 presenta el subconjunto de diagramas de clase que utilizaremos.

8

Page 12: Aplicaciones Distribuidas Resumen Apuntrix

Figura 2: Un subconjunto de los diagramas de clases UML.

La arquitectura de aplicaciones distribuidas

La idea de utilizar una arquitectura multicapa para organizar las funciones de una red dedatos se puede aplicar a las aplicaciones distribuidas. La Figura 3 presenta un ejemplo de dichaarquitectura.

Figura 3: Arquitectura de las aplicaciones distribuidas.

Las funciones de una aplicación distribuida se pueden clasificar en tres capas:

La capa de presentación proporciona la interfaz de usuario.

La capa lógica de aplicación proporciona la computación necesaria para la aplicación. Estacapa también se llama capa lógica de negocio para las aplicaciones empresariales.

La capa de servicio proporciona los servicios necesarios para soportar las funciones de lasotras dos capas. Los servicios pueden incluir utilidades de acceso a los datos, servicios dedirectorio para búsquedas de nombres, y comunicación entre procesos.

Este texto se va a centrar en la capa de servicio.

Conjuntos de herramientas, marcos de desarrollo y componentes

Los conjuntos de herramientas (toolkits), entornos de desarrollos (frameworls) y componentesson términos asociados con la ingeniería del software para sistemas empresariales.

Un toolkit o framework es una colección de clases, herramientas y ejemplos de programa-ción. Por ejemplo, el toolkit JDK es una colección de herramientas para desarrollar programasJava,

9

Page 13: Aplicaciones Distribuidas Resumen Apuntrix

El desarrollo de software basado en componentes es una técnica para la construcción desistemas software empresariales. Utilizando esta técnica, el software se desarrolla y evolucionamediante la unión de componentes ya probados y reutilizables.

10

Page 14: Aplicaciones Distribuidas Resumen Apuntrix

2. IPC - Comunicación entre procesos

2.1. Un arquetipo de interfaz de programación para comunicación entre pro-cesos

Para facilitar la comunicación entre procesos se necesitan cuatro operaciones primitivas bási-cas:

Enviar. Se invoca por el proceso emisor con el propósito de transmitir datos al procesoreceptor.

Recibir. Es invocada por el proceso receptor con el objetivo de aceptar datos de un procesoemisor.

Conectar. Para mecanismos de comunicación orientados a conexión deben existir opera-ciones que permitan establecer una conexión lógica entre el proceso que lo invoca y otroproceso determinado.

Desconectar. Para mecanismos de comunicación orientados a conexión, permite que unaconexión lógica sea liberada en ambos extremos de la comunicación.

2.2. Sincronización de eventos

Una de las mayores dificultades cuando se trabaja con mecanismos de comunicación entreprocesos es que cada proceso involucrado se ejecuta de forma independiente sin que ningunode ellos sepa qué ocurre en el proceso en el otro extremo.

La forma más sencilla que tiene un mecanismo de comunicación de procesos para proporcio-nar sincronización de eventos es por medio de peticiones bloqueantes, que es la supresión de laejecución del proceso hasta que la operación invocada haya finalizado.

Durante su ejecución, el proceso se suspende después de que se invoque cada llamada blo-queante. Cada vez que se ejecuta una invocación a una operación bloqueante, la condición debloqueo se inicia por las funcionalidades de comunicación entre procesos en conjunto con el sis-tema operativo sobre el que se apoya. En el caso de que la operación no pueda ser completada,un proceso bloqueado sufrirá un bloqueo indefinido, durante el cual el proceso permaneceráen el estado de bloqueado indefinidamente, a menos que se tomen las medidas de intervenciónapropiadas.

Las operaciones bloqueantes a menudo se llaman operaciones síncronas. Como alternati-va, las operaciones de comunicación entre procesos también pueden ser asíncronas o no blo-queantes. Una operación asíncrona invocada por un proceso no causará bloqueo, y se informaráposteriormente al proceso si la operación se ha completado y si lo ha hecho con éxito o no.

2.3. Temporizadores e hilos de ejecución

Por lo general es inaceptable que un proceso se quede suspendido de forma indefinida.Existen dos medidas para solucionar este problema. La primera es el uso de temporizadores(timeouts), que se pueden utilizar para fijar el tiempo máximo de bloqueo. En segundo lugar,un proceso puede lanzar otro proceso hijo o un hilo de ejecución (thread) independiente parainvocar la operación bloqueante, permitiendo de esta manera al hilo de ejecución principal o alproceso padre del programa seguir ejecutando otras tareas de procesamiento mientras el hilo deejecución o proceso hijo se suspende.

Los temporizadores son importantes si la ejecución de operaciones síncronas puede poten-cialmente dar como resultado un bloqueo indefinido.

2.4. Interbloqueos y temporizadores

Otra causa de sufrir un bloqueo indefinido son los interbloqueos (deadblocks). Un interblo-queo puede causarse por una operación invocada de forma no apropiada. La Figura 4 muestraeste caso. El proceso 1 ha invocado una operación de recibir para recoger datos del proceso 2.A la vez, el proceso 2 ha invocado otro recibir bloqueante cuando debería ser una operación deenviar lo más apropiado. Cada proceso por su parte se encontrará suspendido indefinidamentehasta que salte un temporizador o hasta que el sistema operativo aborte el proceso.

11

Page 15: Aplicaciones Distribuidas Resumen Apuntrix

Figura 4: Un interbloqueo causado por operaciones bloqueantes.

2.5. Representación de datos

En el nivel físico de una arquitectura de red (el nivel más bajo), los datos se transmiten comoseñales analógicas, las cuales representan un flujo binario. En el nivel de aplicación, se necesitauna representación más compleja de los datos transmitidos con el objeto de dar soporte a larepresentación de tipos de datos y estructuras.

Si consideramos el caso simple de dos procesos, proceso 1 en el ordenador A y proceso 2 enel ordenador B, donde el proceso 1 calcula un valor e invoca una operación enviar para mandarel valor al proceso 2, el cual a su vez invoca una operación recibir para recoger dicho valor; ytodo hecho de acuerdo al protocolo establecido.

Si el ordenador A es una máquina de 32 bits que utiliza representación big-endian y el ordena-dor B una máquina de 16 bits con representación little-endian, supóngase que el dato a transmitires de 32 bits y que es transmitido directamente desde el espacio de almacenamiento del proceso1 al espacio reservado por el proceso 2. Entonces (1) 16 bits de los 32 enviados van a ser trun-cados ya que el tamaño de un entero en el computador B es de sólo 16 bits, y (2) el orden delos bytes de la representación de los enteros debe ser intercambiado de forma que se interpretecorrectamente el mismo valor por parte del proceso receptor.

Los procesos participantes en una comunicación deben tomar las medidas oportunas paraempaquetar e interpretar los datos de forma apropiada. Para nuestro ejemplo, hay tres esquemasposibles:

1. Antes de invocar a la operación enviar, el proceso 1 convierte el valor entero a 16 bits enformato little-endian para el proceso 2.

2. El proceso 1 envía los datos en 32 bits y representación big-endian. Tras recibir los datos, elproceso 2 convierte el valor a su formato, 16 bits y little-endian.

3. Los procesos intercambian los datos atendiendo a una representación externa: los datos sevan a enviar transformados a esa representación y los datos recibidos se van a interpretarcon esa representación para luego traducirlos a la representación nativa.

El término empaquetamiento de datos (data marshaling) se usa en el contexto de los mecanismosde comunicación entre procesos para referirse a las transformaciones necesarias para transmitirvalores de datos o estructuras.

Debido a la complejidad existente, el empaquetado de objetos (datos y métodos de un objetode algún lenguaje orientado a objetos como Java) implica un mayor reto que el del resto deestructuras, por lo que se le ha dado un nombre específico: serialización de objetos.

2.6. Codificación de datos

Las aplicaciones distribuidas de propósito general necesitan un esquema universal, e inde-pendiente de plataforma, para codificar el intercambio de datos. Como se muestra en la Figura5, hay estándares para la codificación de datos disponibles a diferentes niveles de abstracción.

12

Page 16: Aplicaciones Distribuidas Resumen Apuntrix

Figura 5: Estándares de representación de datos de red.

2.7. Protocolos basados en texto

El empaquetamiento de datos es, en el caso más simple, cuando se intercambian cadenas decaracteres o texto codificado en una representación de tipo ASCII. Tiene la ventaja adicional deque puede ser fácilmente analizado por un programa y mostrado a un usuario humano. Estosprotocolos se denominan basados en texto, como por ejemplo FTP, HTTP y SMTP.

2.8. Protocolos de solicitud-respuesta

En estos protocolos un lado invoca una petición y espera una respuesta del otro extremo.Posteriormente, puede ser enviada otra solicitud, esperándose de nuevo respuesta. El protocolose desarrolla basándose en interacciones de este tipo hasta que la tarea solicitada se ha cumplido.FTP, HTTP y SMTP son protocolos habituales del tipo solicitud-respuesta.

2.9. Diagrama de eventos y diagrama de secuencia

Un diagrama de eventos es un diagrama que se puede utilizar para documentar la secuenciadetallada de eventos y bloqueos durante la ejecución de un protocolo. La Figura 6 es un diagramade eventos para un protocolo solicitud-respuesta en el que participan dos procesos concurrentes,A y B.

Cabe resaltar que cada turno de solicitud-respuesta enlaza una pareja de operaciones enviary recibir para intercambiar dos mensajes. El protocolo se puede extender hasta cualquier númerode turnos de intercambios con este patrón.

Figura 6: Un diagrama de eventos.

También es esencial que los programas que implementan el protocolo estén escritos para

13

Page 17: Aplicaciones Distribuidas Resumen Apuntrix

invocar las operaciones de enviar y recibir en el orden preestablecido, de otra forma puedenquedarse bloqueados de forma indefinida.

La Figura 7 presenta, por medio de un diagrama de eventos, un protocolo HTTP. En su formamás básica, HTTP es un protocolo basado en texto del tipo petición-respuesta que utiliza sólo unturno de intercambio de mensajes. Un servidor web es un proceso que escucha constantementepeticiones realizadas desde procesos navegadores.

Figura 7: Diagrama de eventos de una sesión HTTP.

Una forma simplificada de este diagrama, denominada diagrama de secuencia y parte dela notación UML, se usa más habitualmente para denotar la comunicación entre procesos. Enun diagrama de secuencia, no se diferencia entre estados de bloqueo y ejecución. Cada mensajeintercambiado se representa con una línea dirigida, tal y como se muestra en la Figura 8.

Figura 8: Un diagrama de secuencia.

La Figura 9 muestra el texto de los mensajes intercambiados durante una sesión HTTP deejemplo. Por medio de un cliente telnet se puede conectar a un servidor web e introducir el textode una petición HTTP a mano.

2.10. Comunicación entre procesos orientada y no orientada a conexión

Por medio de un mecanismo de IPC orientado a conexión, dos procesos establecen una co-nexión y posteriormente, insertan datos en extraen datos desde dicha conexión. Una vez que laconexión es establecida, no es necesaria la identificación de emisor y receptor.

Para el caso de una IPC no orientada a conexión, los datos son intercambiados por medio depaquetes independientes cada uno de los cuales necesita explícitamente la dirección del receptor.

2.11. Evolución de los paradigmas de comunicación entre procesos.

Veremos diferentes modelos, o paradigmas, por medio de los cuales la comunicación entreprocesos se proporciona al programador que quiere utilizar una IPC en su programa.

En el nivel menos abstracto, la comunicación entre procesos implica la transmisión de ristrasbinarias sobre una conexión, serie o paralelo. Este paradigma puede ser válido para el desarrollodel software de un driver de red. No se verá en este resumen.

14

Page 18: Aplicaciones Distribuidas Resumen Apuntrix

Figura 9: El diálogo durante una sesión HTTP.

El siguiente nivel es un paradigma bien conocido, denominado interfaz de programación deaplicaciones de sockets. (el API de sockets). Por medio del paradigma de sockets, dos procesosintercambian datos por medio de una estructura lógica denominada socket, habiendo uno decada tipo en cada extremo. Los datos a transmitir se escriben sobre el socket. En el otro extremo,un receptor lee o extrae datos del socket. Se verá en el Capítulo 3.

Los paradigmas de llamadas a procedimientos remotos o de invocación de métodos remo-tos proporcionan una mayor abstracción, permitiendo al proceso realizar llamadas a procedi-mientos o la invocación de métodos de un proceso remoto, con la transmisión de datos comoargumentos o valores de resultado. Se verá en el Capítulo 8.

15

Page 19: Aplicaciones Distribuidas Resumen Apuntrix

3. Paradigmas de computación distribuida

3.1. Paradigmas y abstracción

Abstracción

La abstracción es la idea de encapsulación, o de ocultamiento de detalles. La abstracción sematerializa en proporcionar herramientas o funcionalidades que permitan el desarrollo de soft-ware sin que el programador tenga que conocer las complejidades subyacentes. Por ejemplo, seutilizan compiladores para abstraerse del detalle de los lenguajes máquina, y los programadoresJava utilizan el paquete AWT para desarrollar rápidamente interfaces gráficas.

Paradigmas

El diccionario Webster define la palabra paradigma como “un patrón, ejemplo o modelo”.Es útil identificar los patrones o modelos básicos y clasificar los detalles de acuerdo con estosmodelos. Este capítulo busca presentar una clasificación de los paradigmas sobre aplicacionesdistribuidas. Los paradigmas se van a presentar ordenados basándose en su nivel de abstracción,como se muestra en la Figura 10.

Figura 10: Los paradigmas de computación distribuida y su nivel de abstracción.

3.2. Una aplicación de ejemplo

A través del resto de este capítulo, se usará una misma aplicación para estudiar cómo seaplica cada uno de los paradigmas.

Se trata de un sistema de subastas on-line. (Las implementaciones descritas intencionadamen-te ignoran detalles de la aplicación real). Se simplificará el sistema hasta el punto de tratar sóloun objeto a subastar en cada sesión. Durante cada sesión de subasta, un objeto está abierto apujas emitidas por los participantes en la subasta. Al final de la sesión, el subastador anuncia elresultado. Se va a centrar la atención en los aspectos de computación distribuida de la capa deservicio (esto es, en el nivel de servicio subyacente que da soporte al resto de niveles superiores)de la arquitectura de la aplicación.

3.3. Paradigmas para aplicaciones distribuidas

Paso de mensajes

La aproximación más básica a la comunicación entre procesos es el paso de mensajes. Losdatos que representan mensajes se intercambian entre dos procesos, un emisor y un receptor.

Es el paradigma fundamental para aplicaciones distribuidas. El mensaje se entrega a un re-ceptor, que procesa la petición y envía un mensaje como respuesta. Las operaciones básicasnecesarias para dar soporte al paradigma de paso de mensajes son enviar y recibir. Para comuni-caciones orientadas a conexión, también se necesitan las operaciones conectar y desconectar. Lasoperaciones sirven para encapsular el detalle de la comunicación a nivel del sistema operativo,de forma que el programador puede hacer uso de operaciones para enviar y recibir mensajes sinpreocuparse por el detalle subyacente.

16

Page 20: Aplicaciones Distribuidas Resumen Apuntrix

La interfaz de programación de aplicaciones de sockets se basa en este paradigma. Usandoun socket, dos procesos pueden intercambiarse datos de la siguiente forma: un emisor escribe oinserta un mensaje en el socket; en el otro extremo, un receptor lee o extrae un mensaje del socket.

Paradigma cliente-servidor

El modelo cliente-servidor asigna roles diferentes a los dos procesos que colaboran. Unproceso, el servidor, interpreta el papel de proveedor de servicios, esperando de forma pasiva lallegada de peticiones. El otro, el cliente, invoca determinadas peticiones al servidor y aguardasus respuestas. La Figura 11 ilustra este paradigma.

Figura 11: El paradigma cliente-servidor.

El modelo cliente-servidor proporciona una abstracción eficiente para facilitar servicios dered. Las operaciones necesarias incluyen aquellas que permiten a un proceso servidor escuchary aceptar peticiones, y a un cliente solicitar dichas peticiones y aceptar las respuestas. La sincro-nización de eventos se simplifica: el proceso servidor espera peticiones, y el cliente en su turnoespera las respuestas.

Cada participante, así como el programa de subastas, asumen a la vez el papel de cliente yservidor, de la siguiente forma:

Para el control de la sesión:

Como servidor, un participante espera escuchar el anuncio del subastador (1) cuando co-mience la sesión, (2) en el momento en el que se produzca un cambio en la puja máxima,y (3) cuando la sesión termine.

Como servidor, el subastador envía una petición que anuncia los tres tipos de eventos antescomentados.

Para la aceptación de pujas:

Como servidor, un participante envía una nueva puja a un servidor.

Como cliente, un subastador acepta nuevas pujas y actualiza la puja máxima.

Paradigma de igual a igual peer-to-peer

En el paradigma cliente-servidor, no se da soporte para que el proceso servidor inicie lacomunicación.

En el paradigma peer-to-peer, los procesos participantes interpretan los mismos papeles,con idénticas capacidades y responsabilidades. Cada participante puede solicitar una petición acualquier otro participante y recibir una respuesta.

El paradigma peer-to-peer resulta más apropiado para aplicaciones como mensajería instantá-nea, transferencia de ficheros, vídeo-conferencia, y trabajo colaborativo. También es posible queuna aplicación se base simultáneamente en los modelos cliente-servidor y peer-to-peer. Naps-ter.com utiliza un servidor como directorio además de la comunicación peer-to-peer.

17

Page 21: Aplicaciones Distribuidas Resumen Apuntrix

Este paradigma se puede implementar por medio de bibliotecas que proporcionen herra-mientas para el paso de mensajes.

La implementación de nuestro sistema de subastas puede simplificarse sustancialmente apli-cando peer-to-peer. Un participante puede conectarse al subastador directamente para registrarseen la subasta. El subastador posteriormente contacta con cada uno de los participantes para ini-ciar la sesión de subasta, durante la cual cada uno de los participantes individualmente puedenobtener el estado y realizar pujas. Al concluir la subasta, el subastador notifica al ganador, y elresto de participantes pueden conocer el resultado contactando con el propio subastador.

Paradigma de sistema de mensajes

El paradigma de sistema de mensajes o Middleware Orientado a Mensajes (MOM), (Figura12) es una elaboración del paradigma básico del paso de mensajes. Middleware

hace referen-cia al softwareque actúacomo interme-diario entreprocesos in-dependientes.Los sistemasde mensajesson unos delos tipos demiddleware, losORB o brokerde peticionesson otros.

Figura 12: El paradigma de sistema de mensajes.

En este paradigma, un sistema de mensajes sirve de intermediario entre procesos separadose independientes. El sistema de mensajes actúa como un conmutador para mensajes, a travésdel cual los procesos intercambian mensajes asíncronamente, de forma desacoplada. Un emisordeposita un mensaje en el sistema de mensajes, el cual redirige el mismo a la cola de mensajesasociada a dicho receptor. Una vez que se ha enviado, el emisor queda liberado para que realicecualquier otra tarea.

Modelo de mensajes punto a puntoEn este modelo, un sistema de mensajes redirige un mensaje desde el emisot hasta la cola demensajes del receptor. El middleware proporciona un depósito de los mensajes que permite queel envío y la recepción estén desacoplados. Un proceso receptor extrae los mensajes de su colade mensajes y procesa cada mensaje de forma correspondiente.

El paradigma de mensajes punto a punto proporciona una abstracción adicional para opera-ciones asíncronas.

La implementación de nuestro sistema de subastas es la misma que con el modelo básico depaso de mensajes. La única diferencia es que los mensajes se canalizan por medio del middleware.

Modelo de mensajes publicación/suscripciónEn este modelo, cada mensaje se asocia con un determinado tema o evento. Las aplicacionesinteresadas en el suceso de un específico evento se pueden suscribir a los mensajes de dichoevento. Cuando el evento que se aguarda ocurre, el proceso publica un mensaje anunciandoel evento o asunto. El middleware del sistema de mensajes distribuye el mensaje a todos lossuscriptores.

El modelo de mensajes publicación/suscripción ofrece una potente abstracción para multidi-fusión o comunicación en grupo.

La implementación de nuestro sistema de subastas se realizaría de la siguiente forma:

Cada participante se suscribe a los mensajes del evento comienzo-subasta.

El subastador anuncia el comienzo de la sesión de subasta enviando un mensaje de eventocomienzo-subasta.

18

Page 22: Aplicaciones Distribuidas Resumen Apuntrix

Tras recibir el evento de comienzo-subasta, cada participante se suscribe a los mensajes delevento fin-subasta-

El subastador se suscribe a los mensajes del evento nueva-puja.

Un participante que desee realizar una nueva puja lanzará el evento nueva-puja, que seráreenviado al subastador.

Al final de la sesión, el subastador lanzará un mensaje fin-subasta para informar a todos losparticipantes del resultado.

Modelo de llamadas a procedimientos remotos

Cuando las aplicaciones crecen en complejidad, resulta necesario un nivel de abstracciónmayor para la programación distribuida. Resultaría deseable tener un paradigma que permitieraque el software distribuido se programase de una manera similar a las aplicaciones convenciona-les que se ejecutan sobre un único procesador. El modelo de llamada a procedimientos remotos(RPC) proporciona dicha abstracción. La comunicación entre dos procesos se realiza utilizandoun concepto similar al de una llamada a un procedimiento local.

En un programa que sólo implica a un único proceso, una llamada a un procedimiento deltipo func(arg1, arg2) implica un salto en flujo de ejecución al código de dicho procedimiento.

Una llamada a un procedimiento remoto implica dos procesos independientes, que puedenresidir en máquinas diferentes, y dispara una acción predefinida en un procedimiento propor-cionado por uno de los procesos. Al finalizar el procedimiento, el proceso devuelve un valor alproceso que ha invocado la llamada. La Figura 13 muestra el paradigma RPC.

Figura 13: El paradigma de llamada a procedimientos remotos.

Para utilizar RPC para implementar nuestro sistema de subastas procederemos de la siguien-te forma:

El programa de subastas proporciona un procedimiento remoto para que cada participantese registre y otro procedimiento para que éstos hagan pujas.

Cada programa participante proporciona los siguientes procedimientos remotos: (1) el quepermite al subastador llamar al participante para anunciar el comienzo de una sesión, (2) elque permite al subastador informar al participante de la puja más alta, y (3) el que permiteque el subastador anuncie el final de la sesión.

Paradigma de objetos distribuidos

Las aplicaciones acceden a objetos distribuidos sobre una red. Los objetos proporcionan méto-dos, a través de cuya invocación una aplicación obtiene acceso a los servicios. Varios paradigmasse basan en la idea de objetos distribuidos.

19

Page 23: Aplicaciones Distribuidas Resumen Apuntrix

Invocación de métodos remotosLa invocación de métodos remotos (RMI) es el equivalente en orientación a objetos de las llama-das a procedimientos remotos. En este modelo, un proceso invoca métodos de un objeto, el cualreside en un ordenador remoto.

Los argumentos se pueden pasar con la invocación, y se puede devolver un valor cuando elmétodo ha concluido.

La implementación de nuestro sistema de subastas es esencialmente la misma que con RPC,la excepción es que los métodos de los objetos reemplazan los procedimientos.

Paradigma basado en Object Request BrokerEn el paradigma basado en Object Request Broker, un proceso solicita una petición a un ORB,el cual redirige la petición al objeto apropiado que proporciona dicho servicio. El paradigmase parece bastante al modelo de invocación de métodos remotos. La diferencia es que el ORBen este paradigma funciona como middleware, permitiendo a una aplicación, como solicitante deun objeto, acceder potencialmente a varios objetos remotos (o locales). El ORB puede funcionartambién como mediador para diferentes objetos heterogéneos, permitiendo la interacción entreobjetos implementados usando diferentes API y/o ejecutando sobre diferentes plataformas.

La implementación del sistema de subastas usando un ORB es similar a la que usa RMI. Conla excepción de que cada objeto (subastador y participante) deben registrarse en el ORB y son,en realidad, invocados por este mismo. Cada participante solicita peticiones al objeto subastadorpara registrarse para la sesión y hacer pujas. A través del ORB, el subastador invoca los métodosde cada participante para anunciar el comienzo de la sesión y actualizar el estado de las pujas,y anunciar el final de la sesión.

Espacio de objetos

El paradigma de Espacio de Objetos asume la existencia de entidades lógicas conocidas comoespacio de objetos. Los participantes en una aplicación convergen en un espacio de objetoscomún. Un suministrador coloca objetos como entidades dentro de un espacio de objetos, y lossolicitantes que se suscriben al espacio pueden acceder a dichas entidades.

Además del grado de abstracción proporcionado por los otros paradigmas, proporciona unespacio virtual o sala de reunión entre suministradores y solicitantes de recursos de red, comoobjetos. Esta abstracción oculta los detalles implicados en la búsqueda de recursos u objetos queson necesarios en paradigmas como la invocación de métodos remotos, ORB, o servicios de red.Además, la exclusión mutua es inherente al paradigma, debido a que un objeto en el espaciopuede sólo ser usado por un participante a la vez.

Para el sistema de subastas, todos los participantes así como el suministrador de servicios sesuscribirían al mismo espacio de objetos. Cada participante depositaría un objeto en el espaciode objetos para registrarse en la sesión y para ser notificado del comienzo de la misma. Al co-mienzo de la sesión, el subastador deposita otro objeto en el espacio de objetos. El objeto contieneinformación sobre el elemento a subastar así como el histórico de las pujas. Un participante quedesee realizar una puja tomará el objeto del espacio y, si así lo quiere, añadirá una nueva puja enel objeto antes de devolverlo al espacio de objetos. Al final de la sesión el subastador retirará elobjeto del espacio y, si así lo quiere, añadirá una nueva puja en el objeto antes de devolverlo alespacio de objetos. Al final de la sesión el subastador retirará el objeto del espacio y contactarácon el participante con la mayor puja.

Paradigma de agentes móviles

Un agente móvil es un programa u objeto transportable. En este paradigma, un agente selanza desde un determinado ordenador. El agente entonces viaja de forma autónoma de unordenador a otro de acuerdo con un itinerario que posee. En cada parada, el agente accede a losrecursos o servicios necesarios y realiza las tareas correspondientes para completar su misión.

El paradigma ofrece la abstracción de programa u objeto transportable. En lugar de inter-cambio de mensajes, los datos son transportados por el programa/objeto mientras el propioobjeto se transfiere entre los participantes.

Proporciona una novedosa forma de implementar nuestro sistema de subastas. En comienzo,cada participante lanza un agente móvil hacia el subastador. El agente transporta la identidad,

20

Page 24: Aplicaciones Distribuidas Resumen Apuntrix

incluyendo la dirección de red, del participante al que representa. Una vez que la sesión hacomenzado el subastador lanza un agente móvil que transporta el itinerario de los participantes,así como la mayor puja. El agente móvil circula entre los participantes y el subastador hasta quefinalice la sesión, en cuyo instante el subastador lanza el agente para dar un recorrido más entretodos los participantes para comunicar el resultado.

Paradigma de servicios de red

En este paradigma los proveedores de servicios se registran en los servidores de directoriode una red. Un proceso que desee un servicio particular contacta con el servidor de directorioen tiempo de ejecución, y, si el servicio está disponible, al proceso se le dará una referencia adicho servicio. Usando esta referencia, el proceso interactuará con el servicio.

Es esencialmente una extensión del paradigma de invocación de métodos remotos. La dife-rencia es que los objetos de servicio se registran en un directorio global. Idealmente, los serviciosse pueden registrar y localizar usando un identificador único global, en cuyo caso el paradigmaofrece un nivel de abstracción extra: transparencia de localización.

La implementación de nuestro sistema de subastas es la misma que bajo el paradigma RMIexcepto que el subastador se registra en el servicio de directorio, permitiendo que los partici-pantes lo localicen.

Paradigma de aplicaciones colaborativas (groupware)

En este modelo para trabajo cooperativo basado en ordenador, los procesos participan engrupo en una sesión colaborativa. Cada proceso participante puede hacer contribuciones a todoso parte del grupo. Los procesos pueden hacer eso usando multidifusión para enviar los datos ousar pizarras o tablones virtuales, los cuales permiten a cada participante leer y escribir datossobre una visualización compartida. Los dos paradigmas groupware se muestran en la Figura 14.

Figura 14: El paradigma de aplicaciones colaborativas.

Para implementar el sistema de subastas usando el paradigma groupware basado en men-sajes, el subastador iniciará un grupo, al que se incorporarán los participantes interesados. Alcomienzo de la sesión, el subastador difundirá un mensaje de multidifusión anunciando el co-mienzo. Durante la sesión, cada puja es un mensaje de multidifusión a todos los participantesde forma que cada uno puede independientemente acceder al estado de la subasta. Finalmen-te, el subastador termina la sesión por medio de un mensaje de multidifusión anunciando elresultado.

Si usamos el paradigma basado en pizarra, el subastador y los participantes comparten unapizarra virtual. El subastador comienza el proceso de puja escribiendo un anuncio sobre lapizarra. Posteriormente, cada participante puede realizar una puja escribiéndola en la pizarra.Finalmente, el subastador termina la sesión escribiendo el anuncio final.

3.4. Comparativa

Una misma aplicación se puede implementar usando cualquiera de los paradigmas. ¿Cómoun desarrollador de software puede decidir la más apropiada para una tarea dada?

Uno debe tener cuidado con lo que ofrece cada una de las diferentes alternativas. Es suficientedecir que cada paradigma o herramienta tiene alguna ventaja sobre los otros.

21

Page 25: Aplicaciones Distribuidas Resumen Apuntrix

Nivel de abstracción frente a sobrecarga

La Figura 15 muestra los paradigmas que se han visto y sus niveles de abstracción corres-pondientes. El desarrollo de una aplicación altamente compleja se puede ver muy ayudado poruna herramienta que ofrece un gran nivel de abstracción. Pero la abstracción tiene un precio: lasobrecarga.

Figura 15: Los paradigmas y los niveles de abstracción.

Una aplicación escrita usando RMI requerirá más recursos del sistema y tardará más enejecutar que otra igual que se comunicase por medio del API de sockets. Por otro lado, RMI yotras herramientas que proporcionan mayor nivel de abstracción permiten que una aplicación sedesarrolle más rápidamente.

Escalabilidad

La complejidad de una aplicación distribuida se incrementa significativamente cuando elnúmero de participantes se incrementa. En la aplicación de ejemplo, el subastador debe manejarlas direcciones de los participantes de forma que pueda anunciar el comienzo y final de la sesión.Además, el subastador tiene que contactar repetidas veces con los participantes para notificarlesla puja más alta. La complejidad crece cuando crece el número de participantes.

Con un conjunto de herramientas de un paradigma de alto nivel, la complejidad de gestionarlos participantes la realiza el sistema. Una aplicación así implementada se puede acomodar a unincremento en el número de participantes sin una complejidad adicional.

Soporte multi-plataforma

Los paradigmas son inherentemente independientes de la plataforma. Las herramientas ba-sadas en los paradigmas, por otro lado, pueden ser dependientes de la plataforma. Una herra-mienta que soporte plataformas heterogéneas necesariamente incrementa la complejidad, si secompara con una que soporte una única plataforma.

Muchas de las tecnologías Java, incluida el API Java RMI y los JavaSpaces, por omisión sóloejecutan sobre máquinas virtuales Java.

Por contraste, CORBA es una arquitectura diseñada para dar soporte multi-plataforma; deforma que las herramientas basadas en esta tecnología pueden soportar programas escritos endiversos lenguajes y también procesos ejecutando sobre distintas plataformas.

22

Page 26: Aplicaciones Distribuidas Resumen Apuntrix

4. El API de sockets

Este capítulo introduce la primera herramienta de programación para implementar comuni-caciones entre procesos: el API de sockets.

El API de sockets es un mecanismo que proporciona un nivel bajo de abstracción para IPC.

4.1. Antecedentes

El API de sockets aparece por por primera vez a principios de la década de los 80 comouna biblioteca de programación que proporcionaba la funcionalidad de IPC en una versión delsistema operativo UNIX (BSD).

Java proporciona el API de sockets como parte de las clases básicas del lenguaje. Todas lasinterfaces de programación de sockets comparten el mismo modelo de paso de mensajes y unasintaxis muy similar. En este capítulo usaremos como caso representativo el API de sockets deJava.

4.2. La metáfora del socket en IPC

Inspirándose en la terminología de la telefonía, el diseñador del API de sockets ha proporcio-nado una construcción de programación denominada socket. Cuando un proceso desea comu-nicarse con otro, debe crear una instancia de tal construcción. Sin embargo, a diferencia de latelefonía primitiva, la comunicación entre los interlocutores puede ser orientada a conexión osin conexión.

4.3. El API de sockets datagrama

Hay dos protocolos fundamentales en el nivel de transporte de la arquitectura de Internet: elprotocolo de datagrama de usuario (UDP) y el protocolo de control de transmisión (TCP).

El protocolo de datagrama de usuario (UDP) permite que un paquete se transporte utilizan-do comunicaciones sin conexión. El paquete de datos transportado de esta manera se denominadatagrama. Cada datagrama es dirigido y transportado individualmente y puede llegar al re-ceptor en cualquier orden.

El protocolo de control de transmisión (TCP) está orientado a conexión y transporta un flujode datos sobre una conexión lógica establecida entre el emisor y el receptor. Se garantiza que losdatos mandados van a ser recibidos en el mismo orden que se enviaron.

El API de sockets de Java proporciona construcciones de programación de sockets que hacenuso tanto del protocolo UDP como TCP. Los sockets que utilizan UDP son conocidos como socketsdatagrama, mientras que los que usan TCP se denominan sockets stream.

El socket datagrama sin conexión

Los sockets datagrama pueden dar soporte tanto a una comunicación sin conexión como auna orientada a conexión en el nivel de aplicación (véase la Figura 16). Se debe a que el soporteen tiempo de ejecución del API de sockets puede crear y mantener conexiones lógicas para losdatagramas intercambiados entre dos procesos, como se mostrará en la próxima sección.

En Java, el API de sockets datagrama proporciona dos clases:

1. La clase DatagramSocket para los sockets.

2. La clase DatagramPacket para los datagramas intercambiados.

Un proceso que quiera mandar o recibir datos utilizando esta API debe instanciar un objetoDatagramSocket, o un socket para abreviar. Se dice que cada socket está enlazado a un puerto UDPde la máquina que es local al proceso.

Para mandar un datagrama a otro proceso, un proceso debe crear un objeto que representael datagrama en sí mismo. Este objeto puede crearse instanciando un objeto DatagramPacketque englobe (1) una referencia a un vector de octetos que contenga los datos de la carga, y (2)la dirección de destino. Una vez que se crea el objeto DatagramPacket y en él se incluyen losdatos de la carga y del destino, el proceso emisor realiza una llamada al método send del objetoDatagramSocket, especificando una referencia al objeto DatagramPacket como argumento.

23

Page 27: Aplicaciones Distribuidas Resumen Apuntrix

Figura 16: Socket datagrama sin conexión y orientado a conexión.

En el proceso receptor, también se debe instanciar un objeto DatagramSocket y enlazarlo a unpuerto local; el número de puerto debe coincidir con el especificado en el paquete datagrama delemisor. Para recibir los datagramas enviados al socket, el proceso crea un objeto DatagramPacketque hace referencia a un vector de octetos y llama a un módulo receive de su objeto DatagramSoc-ket, especificando como argumento una referencia al objeto DatagramPacket.

Con los sockets sin conexión, un socket enlazado a un proceso puede utilizarse para mandardatagramas a diferentes destinos. Es también posible que múltiples procesos manden simultá-neamente datagramas al mismo socket enlazado a un proceso receptor.

La Tabla 4.1 resume los métodos principales y los constructores de la clase DatagramPacket,mientras que la Tabla 4.2 recopila los de la clase DatagramSocket (hay muchos más métodos queno se presentan en estas tablas).

Tabla 4.1: Métodos principales de la clase DatagramPacket.

Método/Constructor Descripción

DatagramPacket(byte[] almacén, int longitud) Construye un paquete datagrama para recibir paquetes delongitud longitud; los datos recibidos se almacenarán en el vectorde octetos asociado a almacén.

DatagramPacket(byte[] almacén, int longitud,InetAddress dirección, int puerto)

Construye un paquete datagrama para enviar paquetes delongitud longitud al socket enlazado al número de puerto y a lamáquina especificados; los datos se almacenan en el vector deoctetos asociado a almacén.

DatagramSocket() Construye un socket datagrama y lo enlaza a cualquier puertodisponible de la máquina local; este constructor lo puede utilizarun proceso que manda datos y no necesita recibirlos.

Sincronización de eventos en los sockets datagramaEn las interfaces de programación de sockets básicas, las operaciones send son no bloqueantes,mientras que las operaciones receive son bloqueantes. Para evitar un bloqueo indefinido, elproceso receptor puede utilizar el método setSoTimeout para fijar un plazo máximo de tiempode bloqueo. Si no se recibe ningún dato durante este plazo se activará una excepción Java (unajava.io.InterruptedIOException) que puede capturarse en el código.

Ejemplo 1. Los Listados 4 y 5 ilustran el código de dos programas que utilizan sockets data-grama para intercambiar una única cadena de datos. El emisor crea un paquete datagrama quecontiene una dirección de destino, mientras que el paquete datagrama del receptor no incluye

24

Page 28: Aplicaciones Distribuidas Resumen Apuntrix

Tabla 4.2: Métodos principales de la clase DatagramSocket.

Método/Constructor Descripción

DatagramSocket(int puerto) Construye un socket datagrama y lo enlaza al puerto especificadoen la máquina local; este número de puerto se puede especificardespués en un paquete datagrama destinado a este socket.

void close() Cierra este objeto datagramSocket.

void receive(DatagramPacket p) Recibe un paquete datagrama utilizando este socket.

void send(DatagramPacket p) Envía un paquete datagrama utilizando este socket.

void setSoTimeout(int plazo) Fija un plazo máximo de espera en milisegundos para lasoperaciones de recepción bloqueantes realizadas con este socket.

una dirección de destino. El socket del emisor se enlaza a un número de puerto no especificadopara que el emisor pueda especificar este número de puerto en su datagrama como destino. Porsimplicidad los programas de ejemplo utilizan una sintaxis rudimentaria para manejar excep-ciones.

Listado 4: Ejemplo1Emisor.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Mandar un mensaje utilizando un socket datagrama sin conexión.6 * Se esperan tres argumentos:7 * <nombre del dominio o dirección IP del receptor>8 * <número de puerto del socket del receptor>9 * <mensaje para mandar>

10 */11 public class Ejemplo1Emisor {12 public static void main(String[] args) {13 if(args.length != 3)14 System.out.println("Se requieren 3 argumentos");15 else {16 try {17 InetAddress maquinaReceptora = InetAddress.getByName(args[0]);18 int puertoReceptor = Integer.parseInt(args[1]);19 String mensaje = args[2];20

21 DatagramSocket miSocket = new DatagramSocket();22 byte[] almacen = mensaje.getBytes();23 DatagramPacket datagrama = new DatagramPacket(almacen, almacen.length,

maquinaReceptora, puertoReceptor);24 miSocket.send(datagrama);25 miSocket.close();26 } //fin try27 catch (Exception e) {28 e.printStackTrace();29 } //fin catch30 } //fin else31 } //fin main32 } //fin class

Listado 5: Ejemplo1Receptor.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Recibir un mensaje utilizando un socket datagrama sin conexión.6 * Se espera un argumento:7 * <número de puerto del socket del receptor>8 */9 public class Ejemplo1Receptor {

10 public static void main(String[] args) {

25

Page 29: Aplicaciones Distribuidas Resumen Apuntrix

11 if(args.length != 1)12 System.out.println("Se requiere 1 argumento");13 else {14 int puerto = Integer.parseInt(args[0]);15 final int MAX_LON = 10; //Longitud máxima en octetos admitida16 try {17 DatagramSocket miSocket = new DatagramSocket(puerto);18 byte[] almacen = new byte[MAX_LON];19 DatagramPacket datagrama = new DatagramPacket(almacen, MAX_LON);20 miSocket.receive(datagrama);21 String mensaje = new String(almacen);22 System.out.println(mensaje);23 miSocket.close();24 } //fin try25 catch (Exception e) {26 e.printStackTrace();27 } // fin catch28 } //fin else29 } //fin main30 } //fin class

Hay algunas anomalías en el comportamiento de los sockets datagrama sin conexión:

Si se manda un datagrama a un socket que el receptor todavía no ha creado, es posible queel datagrama sea desechado. Se puede experimentar con este comportamiento arrancandoEjemplo1Emisor antes de ejecutar Ejemplo1Receptor.

Si el receptor especifica una zona de almacenamiento para el datagrama con un tamaño n,un mensaje recibido con un tamaño en octetos mayor que n se truncará.

Ejemplo 2. Es posible hacer la comunicación dúplex o bidireccional. Para hacerlo así, Ejem-plo1Emisor necesitará enlazar su socket a una dirección específica para que Ejemplo1Receptor pue-da mandar datagramas a esa dirección.

El código de ejemplo en los Listados 6, 7 y 8 ilustra cómo puede llevarse a cabo la comunica-ción dúplex. Se crea una clase llamada MiSocketDatagrama como una subclase de DatagramSocket,con dos métodos de instancia para mandar y recibir un mensaje, respectivamente. El progra-ma Ejemplo2EmisorReceptor instancia un objeto MiSocketDatagrama, a continuación, llama a sumétodo enviaMensaje, seguido por una llamada a su método recibeMensaje. El programa Ejem-plo2ReceptorEmisor instancia un objeto MiSocketDatagrama, a continuación, llama a su métodorecibeMensaje, seguido por una llamada a su método enviaMensaje.

Listado 6: MiSocketDatagrama.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Una subclase de DatagramSocket que envía y recibe mensajes.6 */7 public class MiSocketDatagrama extends DatagramSocket {8 static final int MAX_LON = 10;9

10 MiSocketDatagrama(int numPuerto) throws SocketException {11 super(numPuerto);12 }13

14 public void enviaMensaje(InetAddress maquinaReceptora, int puertoReceptor, Stringmensaje) throws IOException {

15 byte[] almacenEnvio = mensaje.getBytes();16 DatagramPacket datagrama = new DatagramPacket(almacenEnvio, almacenEnvio.length

, maquinaReceptora, puertoReceptor);17 this.send(datagrama);18 }19

20 public String recibeMensaje() throws IOException {21 byte[] almacenRecepcion = new byte[MAX_LON];22 DatagramPacket datagrama = new DatagramPacket(almacenRecepcion, MAX_LON);23 this.receive(datagrama);24 String mensaje = new String(almacenRecepcion);25 return mensaje;

26

Page 30: Aplicaciones Distribuidas Resumen Apuntrix

26 }27 } //fin class

Listado 7: Ejemplo2EmisorReceptor.java

1 import java.net.*;2

3 /**4 * Aplicación que manda y después recibe un mensaje utilizando un socket datagrama5 * sin conexión.6 * Se esperan cuatro argumentos:7 * <nombre de dominio o dirección IP del receptor>8 * <número de puerto del socket datagrama del receptor>9 * <número de puerto del socket datagrama de este proceso>

10 * <mensaje, una cadena, para mandar>11 */12 public class Ejemplo2EmisorReceptor {13 public static void main(String[] args) {14 if(args.length != 4)15 System.out.println("Se requieren 4 argumentos");16 else {17 try {18 InetAddress maquinaReceptora = InetAddress.getByName(args[0]);19 int puertoReceptor = Integer.parseInt(args[1]);20 int miPuerto = Integer.parseInt(args[2]);21 String mensaje = args[3];22 MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);23 miSocket.enviaMensaje(maquinaReceptora, puertoReceptor, mensaje);24 System.out.println(miSocket.recibeMensaje());25 miSocket.close();26 } //fin try27 catch (Exception e) {28 e.printStackTrace();29 } //fin catch30 } //fin else31 } //fin main32 } //fin class

Listado 8: Ejemplo2ReceptorEmisor.java

1 import java.net.*;2

3 /**4 * Aplicación que recibe un mensaje y después lo manda utilizando un socket datagrama5 * sin conexión.6 * Se esperan cuatro argumentos:7 * <nombre de dominio o dirección IP del receptor>8 * <número de puerto del socket datagrama del receptor>9 * <número de puerto del socket datagrama de este proceso>

10 * <mensaje, una cadena, para mandar>11 */12 public class Ejemplo2ReceptorEmisor {13 public static void main(String[] args) {14 if(args.length != 4)15 System.out.println("Se requieren 4 argumentos");16 else {17 try {18 InetAddress maquinaReceptora = InetAddress.getByName(args[0]);19 int puertoReceptor = Integer.parseInt(args[1]);20 int miPuerto = Integer.parseInt(args[2]);21 String mensaje = args[3];22 MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);23 System.out.println(miSocket.recibeMensaje());24 miSocket.enviaMensaje(maquinaReceptora, puertoReceptor, mensaje);25 miSocket.close();26 } //fin try27 catch (Exception e) {28 e.printStackTrace();29 } //fin catch30 } //fin else31 } //fin main

27

Page 31: Aplicaciones Distribuidas Resumen Apuntrix

32 } //fin class

Es también posible que múltiples procesos entablen una comunicación sin conexión de estamanera; es decir, se puede añadir un tercer proceso que también tenga un socket datagrama, deforma que pueda también mandar y recibir de los otros procesos.

El API de sockets datagrama orientados a conexión

Es poco común emplear sockets datagrama para comunicaciones orientadas a conexión; laconexión proporcionada por esta API es rudimentaria y típicamente insuficiente para las aplica-ciones.

La Tabla 4.3 describe dos métodos de la clase DatagramSocket que permiten crear y terminaruna conexión. Para realizar una conexión con un socket, se especifica la dirección de un socketremoto. Una vez hecha tal conexión, el socket se utiliza para intercambiar paquetes de datagramacon el socket remoto. Si se mandan los datos al socket desde una fuente que no corresponde conel socket remoto conectado, los datos se ignorarán. Así, una vez que se asocia una conexión a unsocket datagrama, este socket no estará disponible para comunicarse con otro socket hasta que laconexión se termine. La conexión es unilateral; esto es, sólo se impone en un extremo. El socketen el otro lado está disponible para mandar y recibir datos a otros sockets, a menos que se realiceuna conexión con este socket.

Tabla 4.3: Llamadas de método para un socket datagrama orientado a conexión.

Método/Constructor Descripción

void connect(InetAddress direccion, int puerto) Crea una conexión lógica entre este socket y un socket en ladirección y puerto remotos.

void disconnect() Termina la conexión actual, si existe, de este socket.

Ejemplo 3. El código mostrado en los Listados 9 y 10 ilustra la sintaxis de uso de los socketsdatagrama orientados a conexión. En Ejemplo3Emisor.java, se crea una conexión entre el socketdatagrama del proceso emisor y el del proceso receptor. Nótese que la conexión se hace enambos lados. Una vez que se establece mutuamente una conexión, cada proceso está obligado autilizar su socket para la IPC con otro proceso (esto no prohíbe a cada proceso crear otra conexiónutilizando otro socket). El emisor manda sucesivamente por la conexión 10 copias del mismomensaje. En el proceso receptor, se visualiza inmediatamente cada uno de los diez mensajesrecibidos. El proceso receptor después manda un único mensaje de vuelta al proceso emisorpara ilustrar que la conexión permite una comunicación bidireccional.

Listado 9: Ejemplo3Emisor.java

1 import java.net.*;2

3 /**4 * Aplicación que utiliza un socket datagrama orientado a conexión para mandar5 * múltiples mensajes, y después recibe uno.6 * Se esperan cuatro argumentos:7 * <nombre de dominio o dirección IP del receptor>8 * <número de puerto del socket datagrama del otro proceso>9 * <número de puerto del socket datagrama de este proceso>

10 * <mensaje, una cadena, para mandar>11 */12 public class Ejemplo3Emisor {13 public static void main(String[] args) {14 if(args.length != 4)15 System.out.println("Se requieren 4 argumentos");16 else {17 try {18 InetAddress maquinaReceptora = InetAddress.getByName(args[0]);19 int puertoReceptor = Integer.parseInt(args[1]);20 int miPuerto = Integer.parseInt(args[2]);21 String mensaje = args[3];22

23 MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);24 miSocket.connect(maquinaReceptora, puertoReceptor);

28

Page 32: Aplicaciones Distribuidas Resumen Apuntrix

25 for(int i=0; i<10; i++)26 miSocket.enviaMensaje(maquinaReceptora, puertoReceptor, mensaje);27

28 System.out.println(miSocket.recibeMensaje());29

30 miSocket.disconnect();31 miSocket.close();32 } //fin try33 catch (Exception e) {34 e.printStackTrace();35 } //fin catch36 } //fin else37 } //fin main38 } //fin class

Listado 10: Ejemplo3Receptor.java

1 import java.net.*;2

3 /**4 * Aplicación que utiliza un socket datagrama orientado a conexión para recibir5 * múltiples mensajes, y después envía uno.6 * Se esperan cuatro argumentos:7 * <nombre de dominio o dirección IP del emisor>8 * <número de puerto del socket datagrama del emisor>9 * <número de puerto del socket datagrama de este proceso>

10 * <mensaje, una cadena, para mandar>11 */12 public class Ejemplo3Receptor {13 public static void main(String[] args) {14 if(args != 4)15 System.out.println("Se esperan 4 argumentos");16 else {17 try {18 InetAddress maquinaEmisora = InetAddress.getByName(args[0]);19 int puertoEmisor = Integer.parseInt(args[1]);20 int miPuerto = Integer.parseInt(args[2]);21 String mensaje = args[3];22

23 MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);24 miSocket.connect(maquinaEmisora, puertoEmisor);25 for(int i=0; i<10; i++)26 System.out.println(miSocket.recibeMensaje());27

28 miSocket.enviaMensaje(maquinaEmisora, puertoEmisor, mensaje);29

30 miSocket.close();31 } //fin try32 catch (Exception e) {33 e.printStackTrace();34 } //fin catch35 } //fin else36 } //fin main37 } //fin class

4.4. El API de sockets en modo stream

El API de sockets en modo stream proporciona un modelo de transferencia de datos basadoen la E/S en modo stream de los sistemas operativos Unix. Por definición, un socket en modostream proporciona sólo comunicaciones orientadas a conexión.

En modo stream, los datos se transfieren utilizando el concepto de un flujo de datos continuoque fluye desde una fuente a un destino.

Usando el API, cada uno de los dos procesos crea individualmente un socket en modo stream.A continuación, se forma una conexión entre los sockets. Los datos se escriben, como un flujo decaracteres, dentro del socket del emisor y, a continuación, el receptor puede leerlos a través de susocket.

En Java, las clases ServerSocket y Socket proporcionan el API de sockets en modo stream. Lasintaxis del API está estrechamente vinculada con el paradigma cliente-servidor (Capítulo 5).

29

Page 33: Aplicaciones Distribuidas Resumen Apuntrix

Hay dos tipos de sockets en el API en modo stream:

La clase ServerSocket sirve para aceptar conexiones. Por claridad, se hará referencia a elloscomo sockets de conexión.

La clase Socket proporciona el otro tipo de socket que permite intercambiar datos. Por clari-dad, se hará referencia a ellos como sockets de datos.

Un proceso conocido como el servidor establece un socket de conexión y después se queda a laespera de las peticiones de conexión de otros procesos. Las peticiones se aceptan de una en una.A través del socket de datos, el proceso servidor puede leer y/o escribir del flujo de datos.

A un proceso que desea comunicarse con el servidor se le conoce como un cliente. Un clientecrea un socket, solicita una conexión con el servidor y, una vez aceptada, el socket del cliente seconecta al socket de datos del servidor de manera que el cliente pueda pasar a leer y/o escribirdel flujo de datos.

Operaciones y sincronización de eventos

La clase ServerSocket permite el establecimiento de conexiones mientras que la clase Socketsirve para la transferencia de datos. En las Tablas 4.4 y 4.5 se listan los métodos principales y losconstructores de estas dos clases.

Tabla 4.4: Métodos principales y constructores de la clase ServerSocket.

Método/Constructor Descripción

ServerSocket(int puerto) Crea un socket de servidor en un puerto especificado.

Socket accept() throws IOException Espera que se solicite una conexión a este socket y la acepta. Elmétodo bloquea hasta que se haga una conexión.

void close() throws IOException Cierra este socket.

void setSoTimeout(int plazo) throwsSocketException

Fija un plazo máximo de tiempo de espera (en ms), de maneraque una llamada accept() sobre este socket bloquee durante sóloesta cantidad de tiempo. Si el plazo expira, se activa unajava.io.InterruptedIOException.

Tabla 4.5: Métodos principales y constructores de la clase Socket.

Método/Constructor Descripción

Socket(InetAddress dirección, int puerto) Crea un socket stream y lo conecta al número de puerto y ladirección IP especificados.

void close() throws IOException Cierra este socket.

InputStream getInputStream() throws IOException Devuelve un flujo de entrada para que se puedan leer los datosde este socket.

OutputStream getOutputStream() throwsIOException

Devuelve un flujo de salida para que se puedan escribir los datosen este socket.

void setSoTimeout(int plazo) throwsSocketException

Fija un plazo máximo de bloqueo de manera que una llamadaread() en el InputStream asociado con este socket bloquee sólodurante esta cantidad de tiempo. Si el plazo de tiempo expira, seactiva una java.io.InterruptedIOException().

Respecto a la sincronización de eventos, las siguientes operaciones son bloqueantes:

Accept (aceptación de una conexión). Si no hay ninguna petición esperando, el procesoservidor se suspenderá hasta que llegue una petición de conexión.

La lectura de un flujo de entrada asociado a un socket de datos. Si la cantidad de datospedida no está actualmente presente en el flujo de datos, el proceso que solicita la lecturase bloqueará hasta que se haya escrito una cantidad de datos suficiente en el flujo de datos.

30

Page 34: Aplicaciones Distribuidas Resumen Apuntrix

No se proporcionan métodos read y write específicos, puesto que se deben utilizar los métodosasociados con las clases InputStream y OutputStream para realizar estas operaciones.

La Figura 17 muestra los flujos de ejecución de un programa que espera una petición deconexión y de otro que solicita la conexión.

Figura 17: Flujos de ejecución de un programa que espera una petición de conexión y de otro que la solicita.

Ejemplo 4. Los Listados 11 y 12 ilustran la sintaxis básica para los sockets en modo stream.Ejemplo4AceptadorConexion acepta conexiones estableciendo un objeto ServerSocket en un puertoespecificado. Ejemplo4SolicitanteConexion crea un objeto Socket, especificando como argumentos elnombre de la máquina y el número de puerto del aceptador. Una vez que el aceptador ha aceptadola conexión, escribe un mensaje en el flujo de datos del socket. En el solicitante, el mensaje se leedel flujo de datos y se visualiza.

Listado 11: Ejemplo4AceptadorConexion.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Aplicación que acepta una conexión y recibe un mensaje utilizando un socket6 * en modo stream.7 * Se esperan dos argumentos:8 * <número de puerto del socket de servidor utilizado en este proceso>9 * <mensaje, una cadena, para mandar>

10 */11 public class Ejemplo4AceptadorConexion {12 public static void main(String[] args) {13 if(args.length != 2)14 System.out.println("Se requieren 2 argumentos");15 else {16 try {17 int numPuerto = Integer.parseInt(args[0]);18 String mensaje = args[1];19 ServerSocket socketConexion = new ServerSocket(numPuerto);20 System.out.println("Preparado para aceptar una conexión");21

22 Socket socketDatos = socketConexion.accept();23 System.out.println("Conexión aceptada");24

25 OutputStream flujoSalida = socketDatos.getOutputStream();26 PrintWriter salidaSocket = new PrintWriter(new OutputStreamWriter(

flujoSalida));27 salidaSocket.println(mensaje);28 salidaSocket.flush(); //Escribir los datos en el flujo del socket antes

de cerrarlo29 System.out.println("Mensaje enviado");30 socketDatos.close();31 System.out.println("Socket de datos cerrado");32 socketConexion.close();33 System.out.println("Socket de conexión cerrado");

31

Page 35: Aplicaciones Distribuidas Resumen Apuntrix

34 } //fin try35 catch (Exception e) {36 e.printStackTrace();37 } //fin catch38 } //fin else39 } //fin main40 } //fin class

Listado 12: Ejemplo4SolicitanteConexion.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Aplicación que solicita una conexión y manda un mensaje utilizando un socket6 * en modo stream.7 * Se esperan dos argumentos:8 * <nombre de la máquina del aceptador de la conexión>9 * <número de puerto del aceptador de la conexión>

10 */11 public class Ejemplo4SolicitanteConexion {12 public static void main(String[] args) {13 if(args.length != 2)14 System.out.println("Se requieren 2 argumentos");15 else {16 try {17 InetAddress maquinaAceptadora = InetAddress.getByName(args[0]);18 int puertoAceptador = Integer.parseInt(args[1]);19 Socket miSocket = new Socket(maquinaAceptadora, puertoAceptador);20 System.out.println("Solicitud de conexión concedida");21

22 InputStream flujoEntrada = miSocket.getInputStream();23 BufferedReader socketInput = new BufferedReader(new InputStreamReader(

flujoEntrada));24 System.out.println("Esperando leer");25

26 String mensaje = socketInput.readLine();27 System.out.println("Mensaje recibido");28 System.out.println("\t" + mensaje);29

30 miSocket.close();31 System.out.println("Socket de datos cerrado");32 } //fin try33 catch (Exception e) {34 e.printStackTrace();35 } //fin catch36 } //fin else37 } //fin main38 } //fin class

Para permitir la separación de la lógica de aplicación y la lógica de servicio en los programas,se emplea una subclase que esconde los detalles de los sockets de datos. El Listado 13 muestra elcódigo de la clase MiSocketStream, que proporciona métodos para leer y escribir de un socket dedatos.

Listado 13: MiSocketStream.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Una clase de envoltura de Socket que contiene métodos para mandar y6 * recibir mensajes.7 */8 public class MiSocketStream extends Socket {9 private Socket socket;

10 private BufferedReader entrada;11 private PrintWriter salida;12

13 MiSocketStream(String maquinaAceptadora, int puertoAceptador) throwsSocketException, IOException {

32

Page 36: Aplicaciones Distribuidas Resumen Apuntrix

14 socket = new Socket(maquinaAceptadora, puertoAceptador);15 establecerFlujos();16 }17

18 MiSocketStream(Socket socket) {19 this.socket = socket;20 establecerFlujos();21 }22

23 private void establecerFlujos() {24 InputStream flujoEntrada = socket.getInputStream();25 entrada = new BufferedReader(new InputStreamReader(flujoEntrada));26 OutputStream flujoSalida = socket.getOutputStream();27 salida = new PrintWriter(new OutputStreamWriter(flujoSalida));28 }29

30 public void enviaMensaje(String mensaje) throws IOException {31 salida.println(mensaje);32 salida.flush();33 }34

35 public String recibeMensaje() throws IOException {36 String mensaje = entrada.readLine();37 return mensaje;38 }39

40 public void close() throws IOException {41 socket.close();42 }43 } //fin class

Ejemplo 5. Los Listados 14 y 15 son revisiones del código presentado en los Listados 11 y 12,modificados para utilizar la clase MiSocketStream en vez de la clase Socket de Java.

Listado 14: Ejemplo5AceptadorConexion.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Aplicación que acepta una conexión y recibe un mensaje utilizando un socket6 * en modo stream.7 * Se esperan dos argumentos:8 * <número de puerto del socket de servidor utilizado en este proceso>9 * <mensaje, una cadena, para mandar>

10 */11 public class Ejemplo5AceptadorConexion {12 public static void main(String[] args) {13 if(args.length != 2)14 System.out.println("Se requieren 2 argumentos");15 else {16 try {17 int numPuerto = Integer.parseInt(args[0]);18 String mensaje = args[1];19 ServerSocket socketConexion = new ServerSocket(numPuerto);20 System.out.println("Preparado para aceptar una conexión");21

22 MiSocketStream socketDatos = new MiSocketStream(socketConexion.accept());23 System.out.ptintln("Conexión aceptada");24

25 socketDatos.enviaMensaje(mensaje);26 System.out.println("Mensaje enviado");27

28 socketDatos.close();29 System.out.println("Socket de datos cerrado");30 socketConexion.close();31 System.out.println("Socket de conexión cerrado");32 } //fin try33 catch (Exception e) {34 e.printStackTrace();35 } // fin catch36 } //fin else37 } //fin main

33

Page 37: Aplicaciones Distribuidas Resumen Apuntrix

38 } //fin class

Listado 15: Ejemplo5SolicitanteConexion.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Aplicación que solicita una conexión y manda un mensaje utilizando un socket6 * en modo stream.7 * Se esperan dos argumentos:8 * <nombre de la máquina del aceptador de la conexión>9 * <número de puerto del aceptador de la conexión>

10 */11 public class Ejemplo5SolicitanteConexion {12 public static void main(String[] args) {13 if(args.length != 2)14 System.out.println("Se requieren 2 argumentos");15 else {16 try {17 String maquinaAceptadora = args[0];18 int puertoAceptador = Integer.parseInt(args[1]);19 MiSocketStream miSocket = new MiSocketStream(maquinaAceptadora,

puertoAceptador);20 System.out.println("Solicitud de conexión concedida");21

22 String mensaje = miSocket.recibeMensaje();23 System.out.println("Mensaje recibido:");24 System.out.println("\t" + mensaje);25

26 miSocket.close();27 System.out.println("Socket de datos cerrado");28 } //fin try29 catch (Exception e) {30 e.printStackTrace();31 } //fin catch32 } //fin else33 } //fin main34 } //fin class

Utilizando la subclase MiSocketStream, es mucho más cómodo realizar entrada y salida en elsocket.

4.5. Sockets con operaciones de E/S no bloqueantes

Un proceso que lee de un socket es susceptible de bloquearse. Se pueden utilizar hilos (th-reads), de manera que un hilo de espera realiza una operación de lectura bloqueante, mientrasque otro hilo permanece activo para procesar otras tareas. Sin embargo, la sobrecarga incurridapuede ser perjudicial para el rendimiento.

Como alternativa, hay interfaces de programación de sockets que proporcionan operacionesde E/S no bloqueantes. A partir de la versión 1.4, Java proporciona un nuevo paquete de E/S,java.nio (NIO), que ofrece sockets con operaciones de E/S no bloqueantes.

4.6. El API de sockets seguros

Las interfaces de programación de sockets seguros son interfaces de sockets mejoradas conmedidas de seguridad de datos.

El nivel de sockets seguros

El nivel de sockets seguros (SSL, Secure Sockets Layer) fue un protocolo desarrollado paratransmitir documentos privados sobre Internet. Una API de SSL tiene métodos o funciones si-milares al API de sockets, excepto en que los datos son cifrados antes de que se transmitan sobreuna conexión SSL.

34

Page 38: Aplicaciones Distribuidas Resumen Apuntrix

La extensión de sockets seguros de Java

La extensión de sockets seguros de JAVA (JSSE) es un conjunto de paquetes de Java queposibilita las comunicaciones seguras en Internet. Implementa una versión de los protocolos SSLy TLS (Transport Layer Security) e incluye herramientas para el cifrado de datos, autentificacióndel servidor, integridad de mensajes y autentificación de cliente opcional.

El API de JSSE se caracteriza por tener una sintaxis similar al API de sockets orientados aconexión presentada en este capítulo.

35

Page 39: Aplicaciones Distribuidas Resumen Apuntrix

5. El paradigma cliente-servidor

5.1. Antecedentes

En la informática distribuida, el paradigma cliente-servidor se refiere a un modelo de apli-caciones de red donde los procesos juegan uno de dos diferentes papeles: un proceso servidor,se dedica a gestionar el acceso a algunos servicios de la red, mientras que los procesos clienteacceden al servidor para obtener un servicio de red.

Los servicios de red (ftp, telnet, Daytime, etc.) son la aplicación más popular de la computacióndistribuida. Por servicio de red se entiende un servicio proporcionado para permitir a los usuariosde la red compartir recursos.

5.2. Cuestiones sobre el paradigma cliente-servidor

En la implementación real del paradigma hay un número de cuestiones que se deben afron-tar.

Una sesión de servicio

Se utilizará el término sesión para referirse a la interacción entre el servidor y el cliente.El servicio gestionado por un servidor puede ser accesible a múltiples clientes que quieranutilizarlo, incluso concurrentemente. Cada cliente entabla una sesión separada e independientecon el servidor, durante la cual el cliente conduce un diálogo con el servidor hasta haya obtenidoel servicio deseado.

El protocolo de un servicio

Se necesita un protocolo para especificar las reglas que deben observar el cliente y el servidordurante una sesión de servicio. Especificaciones tales como (1) la manera de localizar el servicio,(2) la secuencia de comunicación entre los procesos, y (3) la representación e interpretación delos datos intercambiados.

Localización del servicioDebe existir un mecanismo que permita que un proceso cliente localice un servidor. En el es-quema más simple, la localización de un servicio es estática y se puede identificar utilizando ladirección del proceso servidor. Este es el esquema usado para los servicios de Internet, donde acada servicio de Internet se le asigna un número de puerto específico.

En un nivel más alto de abstracción, un servicio puede identificarse utilizando un nombrelógico registrado en un directorio o en un registro. El nombre lógico necesitará traducirse a laubicación física del proceso servidor. Si la traducción se realiza en tiempo de ejecución, es posibleque la localización del servicio sea dinámica, en cuyo caso se dice que el servicio es transparentede la ubicación.

Comunicaciones entre procesos y sincronización de eventos

En el modelo cliente-servidor, la interacción de los procesos sigue un patrón de petición-respuesta, el cual se puede repetir indefinidamente hasta que concluya la sesión. Por cada peti-ción realizada, el cliente debe esperar por la respuesta del servidor antes de continuar.

El diálogo en cada sesión sigue un patrón descrito en el protocolo especificado por el servicio.Cualquier implementación del programa cliente o servidor debe adherirse a la especificación delprotocolo. Entre otras cosas, la especificación define (1) la secuencia de intercomunicacionesentre el cliente y el servidor, (2) la sintaxis y la semántica de cada petición y respuesta, y (3) laacción esperada en cada lado al recibir una petición o respuesta determinada.

Representación de datos

La elección de la representación de datos depende de la naturaleza y la necesidad del pro-tocolo. Para un servicio sencillo como Daytime, es lógico utilizar una representación en modotexto.

36

Page 40: Aplicaciones Distribuidas Resumen Apuntrix

Elegir una representación de datos en modo texto para un protocolo tiene la ventaja depermitir que el diálogo sea legible para todos, ya que se puede utilizar E/S en modo textoestándar para mostrar los datos intercambiados.

5.3. Ingeniería de software de un servicio de red

El conjunto de software que se necesita en la máquina cliente para proporcionar un servi-cio o aplicación se denomina software del lado cliente, en contraposición al software del ladoservidor, que incluye al programa servidor. Es posible desarrollar por separado e independien-temente el software en ambos lados.

Se usará el protocolo Daytime como un ejemplo del proceso de desarrollo de un servicio dered.

Arquitectura de software

La arquitectura de software de una aplicación construida utilizando el modelo cliente-servidorse puede describir de la siguiente manera:

Nivel de presentación. En el lado del servidor, se necesita una interfaz de usuario (UI)para permitir arrancar el proceso servidor. En el lado cliente, se necesita que el clienteproporcione una interfaz de usuario mediante la cual un usuario en la máquina clientepueda solicitar el servicio y recibir la respuesta del servidor.

Nivel de lógica de aplicación. En el lado del servidor, necesita obtenerse la hora del día delsistema y mandarla a la máquina cliente. En el lado del cliente, hay que enviar al servidorla petición del usuario y mostrarle la respuesta del servidor.

Nivel de servicio. Los servicios requeridos para dar soporte a la aplicación son (1) en ellado del servidor, una lectura del reloj de la máquina servidora y (2) en ambos lados, unmecanismo de IPC.

Las funcionalidades de los tres niveles deben estar presentes en el software conjunto.

Mecanismo de IPC

El mecanismo IPC seleccionado afectará a cómo las aplicaciones transmiten datos. Se presentala posibilidad de escoger entre (1) un socket datagrama sin conexión, (2) un socket datagramaorientado a conexión, o (3) un socket en modo stream.

Los detalles del mecanismo se esconderán completamente de la lógica de presentación yafectarán únicamente a la lógica de aplicación.

Cliente-servidor Daytime usando sockets datagrama sin conexión

Software del lado clienteLógica de presentación. El Listado 16 presenta la clase ClienteDaytime1.java, que encapsula lalógica de presentación del lado cliente. El código en esta clase se ocupa meramente de obtenerla entrada del usuario y de mostrar la salida al mismo. Se realiza una llamada de método auna clase auxiliar, ClienteDaytimeAuxiliar1.java, el cual esconde los detalles de la lógica de laaplicación.

Lógica de aplicación. La clase ClienteDaytimeAuxiliar1.java (Listado 17) encapsula la lógicade aplicación del lado cliente. Este módulo realiza la IPC para mandar una petición y recibir unarespuesta utilizando una subclase de DatagramSocket, MiSocketDatagramaCliente. A este módulose le esconden los detalles de la utilización de sockets datagrama.

Lógica de servicio. La clase MiSocketDatagramaCliente.java (Listado 18) proporciona los deta-lles del servicio de IPC, en este caso utilizando el API de socket datagrama.

Listado 16: ClienteDaytime1.java

1 import java.io.*;2

3 /**

37

Page 41: Aplicaciones Distribuidas Resumen Apuntrix

4 * Lógica de presentación de un ClienteDaytime.5 */6 public class ClienteDaytime1 {7 public static void main (String[] args) {8 InputStreamReader is = new InputStreamReader(System.in);9 BufferedReader br = new BufferedReader(is);

10 try {11 System.out.println("Bienvenido al cliente Daytime.\n¿Cuál es el nombre de la

máquina servidora?");12 String nombreMaquina = br.readLine();13 if(nombreMaquina.length() == 0)14 nombreMaquina = "localhost";15 System.out.println("¿Cuál es el no de puerto de la máquina servidora?");16 String numPuerto = br.readLine();17 if(numPuerto.lentgth() == 0)18 numPuerto = "13";19 System.out.println("Marca de tiempo recibida del servidor" +

ClienteDaytimeAuxiliar1.obtenerMarcaTiempo(nombreMaquina, numPuerto));20 } //fin try21 catch (Exception e) {22 e.printStackTrace();23 } //fin catch24 } //fin main25 } //fin class

Listado 17: ClienteDaytimeAuxiliar1.java

1 import java.net.*;2

3 /**4 * Módulo que proporciona la lógica de aplicación de un cliente de Daytime.5 */6 public class ClienteDaytimeAuxiliar1 {7 public static String obtenerMarcaTiempo(String nombreMaquina, String numPuerto) {8 String marcaTiempo = "";9 try {

10 InetAddress serverHost = InetAddress.getByName(nombreMaquina);11 int serverPort = Integer.parseInt(numPuerto);12 MiSocketDatagramaCliente miSocket = new MiSocketDatagramaCliente();13 miSocket.enviaMensaje(serverHost, serverPort, "");14 marcaTiempo = miSocket.recibeMensaje();15 miSocket.close();16 } //fin try17 catch (Exception e) {18 e.printStackTrace();19 } //fin catch20 return marcaTiempo();21 }22 } //fin class

Listado 18: MiSocketDatagramaCliente.java

1 import java.io.*;2 import java.net.*;3

4 /**5 * Subclase que contiene métodos para mandar y recibir mensajes.6 */7 public class MiSocketDatagramaCliente extends DatagramSocket {8 static final int MAX_LON = 100;9

10 MiSocketDatagramaCliente() throws SocketException {11 super();12 }13

14 MiSocketDatagramaCliente(int numPuerto) throws SocketException {15 super(numPuerto);16 }17

18 public void enviaMensaje(InetAddress maquinaReceptora, int puertoReceptor, Stringmensaje) throws IOException {

38

Page 42: Aplicaciones Distribuidas Resumen Apuntrix

19 byte[] almacenEnvio = mensaje.getBytes();20 DatagramPacket datagrama = new DatagramPacket(almacenEnvio, almacenEnvio.length

, maquinaReceptora, puertoReceptor);21 this.send(datagrama);22 }23

24 public String recibeMensaje() throws IOException {25 byte[] almacenRecepcion = new byte[MAX_LON];26 DatagramPacket datagrama = new DatagramPacket(almacenRecepción, MAX_LON);27 this.receive(datagrama);28 String.mensaje = new String(almacenRecepcion);29 return mensaje;30 }31

32 } //fin class

Software del lado servidorLógica de presentación. Hay muy poca lógica de presentación en el lado del servidor. En es-te caso, la única entrada de usuario corresponde con el puerto del servidor. En este caso, laúnica entrada de usuario corresponde con el puerto del servidor que se maneja utilizando unargumento en la línea de comandos.

Lógica de aplicación. La clase ServidorDaytime1.java (Listado 19) encapsula la lógica de apli-cación del lado servidor. Este módulo ejecuta un bucle infinito, esperando una petición de uncliente y después dirige una sesión de servicio para ese cliente. El módulo realiza la IPC pararecibir una petición y manda una respuesta utilizando una subclase de DatagramSocket, MiSoc-ketDatagramaServidor.

Lógica de servicio. La clase MiSocketDatagramaServidor (Listado 20) proporciona los detallesdel servicio de IPC, en este caso utilizando el API de sockets datagrama. Esta clase devuelve unobjeto de la clase MensajeDatagrama (Listado 21) que contiene la dirección del emisor, así comoel mensaje en sí mismo. El servidor necesita la dirección del emisor para mandar una petición alcliente. Ésta es una idiosincrasia del socket sin conexión: el servidor no tiene manera de conocerdónde mandar una respuesta en caso contrario.

Listado 19: ServidorDaytime1.java

1 import java.io.*;2 import java.util.Date;3

4 /**5 * Módulo que contiene la lógica de aplicación de un servidor Daytime que6 * utiliza un socket datagrama para la comunicación entre procesos.7 * Se espera un argumento:8 * <Puerto de escucha del servidor>9 */

10 public class ServidorDaytime1 {11 public static void main (String[] args) {12 int puertoServidor = 13; //por defecto13 if(args.length == 1)14 puertoServidor = Integer.parseInt(args[0]);15 try {16 MiSocketDatagramaServidor miSocket = new MiSocketDatagramaServidor(

puertoServidor);17 System.out.println("Servidor Daytime preparado");18 while (true) {19 MensajeDatagrama peticion = miSocket.recibeMensajeYEmisor();20 System.out.println("Petición recibida");21 Date marcaTiempo = new Date();22 System.out.println("Marca de tiempo enviada: " + marcaTiempo.toString());23 miSocket.enviaMensaje(peticion.obtieneDireccion(), peticion.obtienePuerto

(), marcaTiempo.toString());24 } //fin while(true)25 } //fin try26 catch (Exception e) {27 e.printStackTrace();28 } //fin catch29 } //fin main30 } //fin class

39

Page 43: Aplicaciones Distribuidas Resumen Apuntrix

Listado 20: MiSocketDatagramaServidor.java

1 import java.net.*2 import java.io.*;3

4 /**5 * Subclase de DatagramSocket que contiene métodos para mandar y6 * recibir mensajes.7 */8 public class MiSocketDatagramaServidor extends DatagramSocket {9 static final int MAX_LON = 100;

10

11 miSocketDatagramaServidor(int numPuerto) {12 super(numPuerto);13 }14

15 public void enviaMensaje(InetAddress maquinaReceptora, int puertoReceptor, Stringmensaje) throws IOException {

16 byte[] almacenEnvio = mensaje.getBytes();17 DatagramPacket datagrama = new DatagramPacket(almacenEnvio, almacenEnvio.length

, maquinaReceptora, puertoReceptor);18 this.send(datagrama)19 }20

21 public String recibeMensaje() throws IOException {22 byte[] almacenRecepcion = new byte[MAX_LON];23 DatagramPacket datagrama = new DatagramPacket(almacenRecepcion, MAX_LON);24 this.receive(datagrama);25 String mensaje = new String(almacenRecepcion);26 return mensaje;27 }28

29 public MensajeDatagrama recibeMensajeYEmisor() throws IOException {30 byte[] almacenRecepcion = new byte[MAX_LON];31 DatagramPacket datagrama = new DatagramPacket(almacenRecepcion, MAX_LON);32 this.receive(datagrama);33 MensajeDatagrama valorDevuelto = new MensajeDatagrama();34 valorDevuelto.fijaValor(new String(almacenRecepcion), datagrama.getAddress(),

datagrama.getPort());35 return valorDevuelto;36 }37

38 } //fin class

Listado 21: MensajeDatagrama.java

1 import java.net.*;2

3 /**4 * Clase para utilizar con MiSocketDatagramaServidor para devolver5 * un mensaje y la dirección del emisor.6 */7 public class MensajeDatagrama {8 private String mensaje;9 private InetAddress direccionEmisor;

10 private int puertoEmisor;11

12 public void fijarValor(String mensaje, InetAddress dir, int puerto) {13 this.mensaje = mensaje;14 this.direccionEmisor = dir;15 this.puertoEmisor = puerto;16 }17

18 public String obtieneMensaje() {19 return this.mensaje;20 }21

22 public InetAddress obtieneDireccion() {23 return this.direccionEmisor;24 }25

26 public int obtienePuerto() {27 return this.puertoEmisor;

40

Page 44: Aplicaciones Distribuidas Resumen Apuntrix

28 }29

30 } //fin class

Cliente-servidor Daytime usando sockets en modo stream

Supóngase que se quiere implementar el mismo servicio utilizando en su lugar sockets orien-tados a conexión. Dado que este cambio sólo afecta básicamente a la lógica de servicio, sólose necesitarían hacer modificaciones importantes en las clases de dicho nivel. La lógica de laaplicación, específicamente la clase auxiliar, se necesitará ajustar en consecuencia.

Software del lado clienteLógica de presentación. El Listado 22 presenta la clase ClienteDaytime2, que es igual que Clienet-Daytime1 excepto por un cambio en el nombre de la clase auxiliar, ClienteDaytimeAuxiliar2.

Lógica de aplicación. La clase ClienteDaytimeAuxiliar2 (Listado 23), que encapsula la lógicade aplicación del lado cliente, es similar a la de la clase ClienteDaytimeAuxiliar1, excepto en quese utiliza un socket en modo stream en lugar de un socket datagrama.

Lógica de servicio. La clase MiSocketStream (Listado 24) proporciona los detalles del serviciode IPC, en este caso utilizando el API de sockets en modo stream.

Listado 22: ClienteDaytime2.java

1 import java.io.*;2

3 /**4 * Lógica de presentación de un ClienteDaytime.5 */6 public class ClienteDaytime2 {7 public static void main (String[] args) {8 InputStreamReader is = new InputStreamReader(System.in);9 BufferedReader br = new BufferedReader(is);

10 try {11 System.out.println("Bienvenido al cliente Daytime.\n¿Cuál es el nombre de la

máquina servidora?");12 String nombreMaquina = br.readLine();13 if(nombreMaquina.length() == 0)14 nombreMaquina = "localhost";15 System.out.println("¿Cuál es el no de puerto de la máquina servidora?");16 String numPuerto = br.readLine();17 if(numPuerto.lentgth() == 0)18 numPuerto = "13";19 System.out.println("Marca de tiempo recibida del servidor" +

ClienteDaytimeAuxiliar2.obtenerMarcaTiempo(nombreMaquina, numPuerto));20 } //fin try21 catch (Exception e) {22 e.printStackTrace();23 } //fin catch24 } //fin main25 } //fin class

Listado 23: ClienteDaytimeAuxiliar2.java

1 import java.net.*;2

3 /**4 * Módulo que proporciona la lógica de aplicación de un cliente de Daytime5 * que utiliza un socket en modo stream para IPC.6 */7 public class ClienteDaytimeAuxiliar2 {8 public static String obtenerMarcaTiempo(String nombreMaquina, String numPuerto)

throws Exception {9 String marcaTiempo = "";

10 int puertoServidor = Integer.parseInt(numPuerto);11 System.out.println("Petición de conexión realizada");12 MiSocketStream miSocket = new MiSocketStream(nombreMaquina, puertoServidor);13 marcaTiempo = miSocket.recibeMensaje();14 miSocket.close();

41

Page 45: Aplicaciones Distribuidas Resumen Apuntrix

15 return marcaTiempo();16 }17 } //fin class

Listado 24: MiSocketStream.java

1 import java.io.*;2 import java.net.*;3

4 /**5 * Subclase que contiene métodos para mandar y recibir mensajes6 */7 public class MiSocketStream extends Socket {8 private Socket socket;9 private BufferedReader entrada;

10 private PrintWritter salida;11

12 MiSocketStream(String maquinaAceptadora, int puertoAceptador) throwsSocketException, IOException {

13 socket = new Socket(maquinaAceptadora, puertoAceptador);14 establecerFlujos();15 }16

17 MiSocketStream(Socket socket) throws IOException {18 this.socket = socket;19 establecerFlujos();20 }21

22 private void establecerFlujos() throws IOException {23 InputStream flujoEntrada = socket.getInputStream();24 entrada = new BufferedReader(new InputStreamReader(flujoEntrada));25 OutputStream flujoSalida = socket.getOutputStream();26 salida = new PrintWriter(new OutputStreamWriter(flujoSalida));27 }28

29 public void enviaMensaje(String mensaje) throws IOException {30 salida.println(mensaje);31 salida.flush();32 }33

34 public String recibeMensaje() throws IOException {35 String mensaje = entrada.readLine();36 return mensaje;37 }38

39 } //fin class

Software del lado servidorLógica de presentación. El código de ServidorDaytime2 (Listado 25) es idéntico al de Servidor-Daytime1.

Lógica de aplicación. El código de ServidorDaytime2 (Listado 25) usa el API de sockets enmodo stream para aceptar una conexión. La referencia de socket devuelta se utiliza después parainstanciar un objeto MiSocketStream, cuyo método enviaMensaje se emplea para transmitir unamarca de tiempo al cliente en el otro extremo de la conexión.

Lógica de servicio. La misma clase de envoltura utilizada en el cliente, MiSocketStream (Lis-tado 24), se utiliza también en el servidor, ya que contiene los métodos necesarios para la IPC enmodo stream.

Listado 25: ServidorDaytime2.java

1 import java.net.*;2 import java.io.*;3 import java.util.Date;4

5 /**6 * Módulo que contiene la lógica de aplicación de un servidor Daytime que7 * utiliza un socket orientado a conexión para la comunicación entre procesos.8 * Se espera un argumento:

42

Page 46: Aplicaciones Distribuidas Resumen Apuntrix

9 * <Puerto de escucha del servidor>10 */11 public class ServidorDaytime2 {12 public static void main (String[] args) {13 int puertoServidor = 13; //por defecto14 if(args.length == 1)15 puertoServidor = Integer.parseInt(args[0]);16 try {17 ServerSocket miSocketConexion = new ServerSocket(puertoServidor);18 System.out.println("Servidor Daytime preparado");19 while (true) {20 MiSocketStream miSocketDatos = new MiSocketStream(miSocketConexion.accept

());21 System.out.println("Petición recibida");22 Date marcaTiempo = new Date();23 System.out.println("Marca de tiempo enviada: " + marcaTiempo.toString());24 miSocketDatos.enviaMensaje(marcaTiempo.toString());25 miSocketDatos.close();26 } //fin while(true)27 } //fin try28 catch (Exception e) {29 e.printStackTrace();30 } //fin catch31 } //fin main32 } //fin class

Prueba de un servicio de red

Es notoriamente difícil probar el buen funcionamiento del software de red. Algunos consejosque pueden ser útiles son:

Utilice la arquitectura de tres niveles y organice en módulos cada nivel tanto en el ladocliente como en el lado servidor.

Use una estrategia gradual o paso a paso en el desarrollo de cada módulo.

Desarrolle en primer lugar el cliente. A veces es útil emplear un servidor de Echo, cuyacorrección sea ya conocida y que use un mecanismo IPC compatible, para probar el clienteindependientemente del servidor.

Utilice mensajes de diagnóstico dentro del código fuente.

Compruebe el conjunto cliente-servidor en una única máquina antes de ejecutar los pro-gramas en máquinas separadas.

5.4. Servidores orientados a conexión y sin conexión

El protocolo Echo permite a un cliente simplemente mandar líneas de texto a un servidor,y recibir un eco de cada una de ellas. Puede usarse el servidor Echo por defecto de cualquiermáquina en Internet como un servidor sustituto temporal cuando un ingeniero de software estádesarrollando un cliente para otro protocolo.

Cliente-servidor Echo sin conexión

Los Listados 26, 27 y 28 presentan una implementación del servicio Echo utilizando el APIde sockets datagrama sin conexión.

El cliente Echo La lógica de presentación se encapsula en la clase ClienteEcho1. El envío de unacadena de texto y la recepción del eco devuelto se maneja mediante un método, obtenerEco, de laclase ClienteEchoAuxiliar1. La clase ClienteEchoAuxiliar1 proporciona la lógica de aplicación delcliente. Se crea una instancia de esta clase por cada proceso cliente.

43

Page 47: Aplicaciones Distribuidas Resumen Apuntrix

El servidor Echo ServidorEcho1.java combina la lógica de presentación y la lógica de aplicaciónpara el servidor. En cada iteración de un bucle infinito, el servidor lee una línea del socket ydespués escribe la línea de vuelta al socket, dirigiendo la respuesta al emisor. Es posible queel servidor interaccione con diferentes clientes en iteraciones sucesivas, resultando sesiones deservicio concurrentes intercaladas.

Listado 26: ClienteEcho1.java

1 import java.io.*;2

3 /**4 * Módulo que contiene la lógica de aplicación de un cliente Echo.5 */6 public class ClienteEcho1 {7 static final String mensajeFin = ".";8

9 public static void main (String[] args) {10 InputStreamReader is = new InputStreamReader(System.in);11 BufferedReader br = new BufferedReader(is);12 try {13 System.out.println("Bienvenido al cliente Echo.\n¿Cuál es el nombre de la

máquina servidora?");14 String nombreMaquina = br.readLine();15 if(nombreMaquina.length == 0)16 nombreMaquina = "localhost";17 System.out.println("Introduzca el no de puerto de la máquina servidora");18 String numPuerto = br.readLine();19 if(numPuerto.length == 0)20 numPuerto = "7";21 ClienteEchoAuxiliar1 auxiliar = new ClienteEchoAuxiliar1(nombreMaquina,

numPuerto);22

23 boolean hecho = false;24 String mensaje, eco;25 while(!hecho) {26 System.out.println("Escriba una línea para recibir el eco, o un único

punto \".\" para terminar");27 mensaje = br.readLine();28 if((mensaje.trim()).equals(mensajeFin)) {29 hecho = true;30 auxiliar.hecho();31 } else {32 eco = auxiliar.obtenerEco(mensaje);33 System.out.println(eco);34 }35 } //fin while36 } //fin try37 catch (Exception e) {38 e.printStackTrace();39 } //fin catch40 } //fin main41 } //fin class

Listado 27: ClienteEchoAuxiliar1.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Módulo que proporciona la lógica de applicación para un cliente Echo6 * utilizando un socket datagrama sin conexión.7 */8 public class ClienteEchoAuxiliar1 {9 private MiSocketDatagramaCliente miSocket;

10 private InetAddress maquinaServidora;11 private int puertoServidor;12

13 ClienteEchoAuxiliar1(String nombreMaquina, String numPuerto) throwsSocketException, UnknownHostException {

14 this.maquinaServidora = InetAddress.getByName(nombreMaquina);15 this.puertoServidor = Integer.parseInt(numPuerto);

44

Page 48: Aplicaciones Distribuidas Resumen Apuntrix

16 this.miSocket = new MiSocketDatagramaCliente();17 }18

19 public String obtenerEco(String mensaje) throws SocketException, IOException {20 String eco = "";21 miSocket.enviaMensaje(maquinaServidora, puertoServidor, mensaje);22 eco = miSocket.recibeMensaje();23 return eco;24 }25

26 public void hecho() throws SocketException {27 miSocket.close();28 }29

30 } //fin class

Listado 28: ServidorEcho1.java

1 import java.io.*;2

3 /**4 * Módulo que contiene la lógica de aplicación de un servidor Echo que utiliza un

socket5 * datagrama sin conexión para la IPC.6 * Requiere un argumento:7 * <número de puerto del servidor>8 */9 public class ServidorEcho1 {

10 public static void main (String[] args) {11 int puertoServidor = 7;12 if (args.length == 1)13 puertoServidor = Integer.parseInt(args[0]);14 try {15 MiSocketDatagramaServidor miSocket = new MiSocketDatagramaServidor(

puertoServidor);16 System.out.println("Servidor Echo preparado");17 while(true) {18 MensajeDatagrama peticion = miSocket.recibeMensajeYEmisor();19 System.out.println("Petición recibida");20 String mensaje = peticion.obtieneMensaje();21 System.out.println("Mensaje recibido: " + mensaje);22 // Enviar el echo23 miSocket.enviaMensaje(peticion.obtieneDireccion(), peticion.obtienePuerto

(), mensaje);24 } //fine while(true)25 } //fin try26 catch (Exception e) {27 e.printStackTrace();28 } //fin catch29 } //fin main30 } //fin class

Cliente-servidor Echo orientado a conexión

Los Listados 29, 30 y 31 presentan una implementación de un cliente y un servidor del servi-cio Echo utilizando el API de sockets en modo stream. La implementación de la lógica de presen-tación (en ClienteEcho2 y ServidorEcho2) es igual que *Echo1. Sin embargo, la lógica de aplicación(en ClienteEchoAuxiliar2 y ServidorEcho2), así como la lógica de servicio (en MiSocketStream) sondiferentes.

Listado 29: ClienteEcho2.java

1 import java.io.*;2

3 /**4 * Módulo que contiene la lógica de aplicación de un cliente Echo.5 */6 public class ClienteEcho2 {7 static final String mensajeFin = ".";

45

Page 49: Aplicaciones Distribuidas Resumen Apuntrix

8

9 public static void main (String[] args) {10 InputStreamReader is = new InputStreamReader(System.in);11 BufferedReader br = new BufferedReader(is);12 try {13 System.out.println("Bienvenido al cliente Echo.\n¿Cuál es el nombre de la

máquina servidora?");14 String nombreMaquina = br.readLine();15 if(nombreMaquina.length == 0)16 nombreMaquina = "localhost";17 System.out.println("Introduzca el no de puerto de la máquina servidora");18 String numPuerto = br.readLine();19 if(numPuerto.length == 0)20 numPuerto = "7";21 ClienteEchoAuxiliar2 auxiliar = new ClienteEchoAuxiliar2(nombreMaquina,

numPuerto);22

23 boolean hecho = false;24 String mensaje, eco;25 while(!hecho) {26 System.out.println("Escriba una línea para recibir el eco, o un único

punto \".\" para terminar");27 mensaje = br.readLine();28 if((mensaje.trim()).equals(mensajeFin)) {29 hecho = true;30 auxiliar.hecho();31 } else {32 eco = auxiliar.obtenerEco(mensaje);33 System.out.println(eco);34 }35 } //fin while36 } //fin try37 catch (Exception e) {38 e.printStackTrace();39 } //fin catch40 } //fin main41 } //fin class

Listado 30: ClienteEchoAuxiliar2.java

1 import java.net.*;2 import java.io.*;3

4 /**5 * Módulo que proporciona la lógica de applicación para un cliente Echo6 * utilizando un socket en modo stream.7 */8 public class ClienteEchoAuxiliar2 {9 static final String mensajeFin = ".";

10 private MiSocketStream miSocket;11 private InetAddress maquinaServidora;12 private int puertoServidor;13

14 ClienteEchoAuxiliar2(String nombreMaquina, String numPuerto) throwsSocketException, UnknownHostException {

15 this.maquinaServidora = InetAddress.getByName(nombreMaquina);16 this.puertoServidor = Integer.parseInt(numPuerto);17 this.miSocket = new MiSocketStream(nombreMaquina, this.puertoServidor);18 System.out.println("Petición de conexión hecha");19 }20

21 public String obtenerEco(String mensaje) throws SocketException, IOException {22 String eco = "";23 miSocket.enviaMensaje(mensaje);24 eco = miSocket.recibeMensaje();25 return eco;26 }27

28 public void hecho() throws SocketException, IOException {29 miSocket.enviaMensaje(mensajeFin);30 miSocket.close();31 }

46

Page 50: Aplicaciones Distribuidas Resumen Apuntrix

32

33 } //fin class

Listado 31: ServidorEcho2.java

1 import java.io.*;2 import java.net.*;3

4 /**5 * Módulo que contiene la lógica de aplicación de un servidor Echo que utiliza un6 * socket en modo stream para la IPC.7 * Requiere un argumento:8 * <número de puerto del servidor>9 */

10 public class ServidorEcho2 {11 static final String mensajeFin = ".";12

13 public static void main (String[] args) {14 int puertoServidor = 7;15 String mensaje;16 if (args.length == 1)17 puertoServidor = Integer.parseInt(args[0]);18 try {19 ServerSocket miSocketConexion = new ServerSocket(puertoServidor);20 System.out.println("Servidor Echo preparado");21 while(true) {22 System.out.println("Espera una conexión");23 MiSocketStream miSocketDatos = new MiSocketStream(miSocketConexion.accept

());24 System.out.println("Conexion aceptada");25 boolean hecho = false;26

27 while(!hecho) {28 mensaje = miSocketDatos.recibeMensaje();29 System.out.println("Mensaje recibido: " + mensaje);30 if((mensaje.trim()).equals(mensajeFin)) {31 System.out.println("Final de la sesión");32 miSocketDatos.close();33 hecho = true;34 } else {35 miSocketDatos.enviaMensaje(mensaje);36 }37 } //fin while(!hecho)38

39 } //fin while(true)40 } //fin try41 catch (Exception e) {42 e.printStackTrace();43 } //fin catch44 } //fin main45 } //fin class

5.5. Servidor iterativo y servidor concurrente

Con un servidor orientado a conexión como ServidorDaytime2 y ServidorEcho2, no hay sola-pamiento de sesiones de cliente, ya que el servidor se limita a intercambiar datos con un clientecuya conexión ha aceptado. A este tipo de servidor se le denomina servidor iterativo, ya quesirve a un cliente cada vez. Cuando se solicita un servicio a un servidor iterativo, un cliente sebloqueará hasta que se sirvan todos los clientes precedentes.

La solución a este problema es introducir concurrencia en el servidor, dando lugar a unservidor concurrente, que es capaz de gestionar múltiples sesiones de cliente en paralelo. Unservidor concurrente se puede implementar con hilos o con operaciones de IPC asíncronas.

Un servidor concurrente utiliza un único socket de conexión para escuchar las conexiones.Sin embargo, se crea un nuevo hilo para aceptar cada conexión y dirigir una sesión de serviciocon el cliente conectado; de manera que el hilo termina cuando concluye la sesión.

Los Listados 32 y 33 presentan el servidor concurrente y la clase que define el hilo queutiliza, respectivamente. Nótese que no se necesita ningún cambio en el código del lado del

47

Page 51: Aplicaciones Distribuidas Resumen Apuntrix

cliente: puede utilizarse ClienteEcho2 para acceder a ServidorEcho3 sin ningún cambio.

Listado 32: ServidorEcho3.java

1 import java.io.*;2 import java.net.*;3

4 /**5 * Módulo que contiene la lógica de aplicación de un servidor Echo que utiliza un6 * socket en modo stream para la IPC. Los clientes se sirven concurrentemente.7 * Requiere un argumento:8 * <número de puerto del servidor>9 */

10 public class ServidorEcho3 {11 public static void main (String[] args) {12 int puertoServidor = 7;13 String mensaje;14 if (args.length == 1)15 puertoServidor = Integer.parseInt(args[0]);16 try {17 ServerSocket miSocketConexion = new ServerSocket(puertoServidor);18 System.out.println("Servidor Echo preparado");19 while(true) {20 System.out.println("Espera una conexión");21 MiSocketStream miSocketDatos = new MiSocketStream(miSocketConexion.accept

());22 System.out.println("Conexion aceptada");23

24 Thread elHilo = new Thread(new HiloServidorEcho(miSocketDatos));25 elHilo.start(); //y continua con el siguiente cliente!26 } //fin while(true)27 } //fin try28 catch (Exception e) {29 e.printStackTrace();30 } //fin catch31 } //fin main32 } //fin class

Listado 33: HiloServidorEcho.java

1 import java.io.*;2

3 /**4 * Módulo diseñado para usarse con un servidor Echo concurrente.5 * El método run() lleva a cabo la lógica de una sesión de cliente.6 */7 public class HiloServidorEcho implements Runnable {8 static final String mensajeFin = ".";9 MiSocketStream miSocketDatos;

10

11 HiloServidorEcho(MiSocketStream miSocketDatos) {12 this.miSocketDatos = miSocketDatos;13 }14

15 public void run() {16 boolean hecho = false;17 String mensaje;18 try {19 while(!hecho) {20 mensaje = miSocketDatos.recibeMensaje();21 System.out.println("Mensaje recibido: " + mensaje);22 if((mensaje.trim()).equals(mensajeFin)) {23 System.out.println("Final de la sesión");24 miSocketDatos.close();25 hecho = true;26 } else {27 miSocketDatos.enviaMensaje(mensaje);28 }29 } //fin while(!hecho)30 } //fin try31 catch (Exception e) {32 e.printStackTrace();

48

Page 52: Aplicaciones Distribuidas Resumen Apuntrix

33 }34 }35

36 } //fin class

5.6. Servidores con estado

Tanto el protocolo Daytime como el Echo pertenecen a una categoría de protocolos conocidacomo protocolos sin estado, en contraste con los protocolos con estado. Un protocolo es sinestado cuando no necesita mantener ninguna información de estado en el servidor.

Un servidor con estado es uno que debe mantener alguna información de estado para propor-cionar su servicio. ¿Qué significa información de estado? Hay dos tipos: información de estadoglobal e información de estado de sesión.

Información de estado global

El servidor mantiene este tipo de información para todos los clientes durante la vida delservidor. Supóngase un protocolo, contador, que requiere que un servidor mantenga un contadoriniciado a 0. Cada vez que un cliente contacta con el servidor, éste incrementa el contador en 1 yenvía su valor actual al cliente. El Listado 34 muestra el código de un servidor que implementael protocolo contador. Los Listados 45 y 36 muestran el programa cliente.

Listado 34: ServidorContador1.java

1 import java.io.*;2

3 /**4 * Módulo que contiene la lógica de aplicación de un servidor Contador5 * que utiliza un socket datagrama para la IPC.6 * Requiere un argumento:7 * <número de puerto del servidor>8 * /9 public class ServidorContador1 {

10 static int contador = 0;11

12 public static void main (String[] args) {13 int puertoServidor = 12345;14 if(args.length == 1)15 puertoServidor = Integer.parseInt(args[0]);16 try {17 MiSocketDatagramaServidor miSocket = new MiSocketDatagramaServidor(

puertoServidor);18 System.out.println("Servidor contador preparado");19 while(true) {20 MensajeDatagrama peticion = miSocket.recibeMensajeYEmisor();21 System.out.println("Petición recibida");22 incremento();23 System.out.println("Contador enviado " + contador);24 miSocket.enviaMensaje(peticion.obtieneDireccion(), peticion.obtienePuerto

(), String.valueOf(contador));25 } //fin while(true)26 } //fin try27 catch (Exception e) {28 e.printStackTrace();29 }30 } //fin main31

32 static private synchronized void incremento() {33 contador++;34 }35

36 } //fin class

Listado 35: ClienteContador1.java

1 import java.io.*;2

49

Page 53: Aplicaciones Distribuidas Resumen Apuntrix

3 /**4 * Módulo que contiene la lógica de presentación de un cliente Contador.5 */6 public class ClienteContador 1 {7 public static void main (String[] args) {8 InputStreamReader is = new InputStreamReader(System.in);9 BufferedReader br = new BufferedReader(is);

10 try {11 System.out.println("Bienvenido al cliente Contador.\n¿Cuál es el nombre de

la máquina servidora?");12 String nombreMaquina = br.readLine();13 if(nombreMaquina.length() == 0)14 nombreMaquina = "localhost";15 System.out.println("¿Cuál es el número de puerto de la máquina servidora?");16 String numPuerto = br.readLine();17 if(numPuerto.length() == 0)18 numPuerto = "12345";19 System.out.println("Contador recibido del servidor: " +

ClienteContadorAuxiliar1.obtenerContador(nombreMaqina, numPuerto));20 } //fin try21 catch (Exception e) {22 e.printStackTrace();23 }24 } //fin main25 } //fin class

Listado 36: ClienteContadorAuxiliar1.java

1 import java.net.*;2

3 /**4 * Módulo que proporciona la lógica de aplicación para un cliente Contador.5 */6 public class ClienteContadorAuxiliar1 {7 public static int obtenerContador(String nombreMaquina, String numPuerto) {8 int contador = 0;9 String mensaje = "";

10 try {11 InetAddress maquinaServidora = InetAddress.getByName(nombreMaquina);12 int puertoServidor = Integer.parseInt(numPuerto);13 MiSocketDatagramaCliente miSocket = new MiSocketDatagramaCliente();14 miSocket.enviaMensaje(maquinaServidora, puertoServidor, "");15 mensaje = miSocket.recibeMensaje();16 System.out.println("Mensaje recibido: " + mensaje);17 contador = Integer.parseInt(mensaje.trim());18 miSocket.close();19 } //fin try20 catch (Exception e) {21 e.printStackTrace();22 }23 return contador;24 }25 } //fin class

Información de estado de sesión

Algunos protocolos o aplicaciones tienen la necesidad de mantener información específicapara una sesión de cliente.

Considérese un servicio de red tal como ftp. Un fichero es típicamente transformado enbloques, requiriéndose varias rondas de intercambios de datos para completar la transferenciadel fichero. La información de estado de cada sesión incluye:

1. El nombre del fichero con el que se está trabajando.

2. El número del bloque actual.

3. La acción (traer, llevar, etc.) que se está realizando sobre el fichero.

Hay al menos dos esquemas para mantener los datos de estado de sesión.

50

Page 54: Aplicaciones Distribuidas Resumen Apuntrix

Servidor sin estado En este esquema, el cliente puede mantener la información de estado desesión de manera que cada petición contenga la información de estado de sesión, permitiendoal servidor procesar cada petición de acuerdo con los datos de estado enviados en la petición.

Servidor con estado En el segundo esquema, el servidor debe mantener la información delestado de la sesión. El servidor controla el progreso de la sesión manteniendo el estado de lamisma.

En los servidores con estado, además de la lógica requerida para mantener los datos delestado, se debe prever la necesidad de salvaguardar la información de estado en el caso de quese interrumpa una sesión.

Otro ejemplo de protocolo con estado corresponde con una aplicación del tipo “cesta dela compra”. Cada sesión debe mantener los datos de estado que hacen el seguimiento de laidentidad del comprador y de los contenidos acumulados en su cesta de compras.

51

Page 55: Aplicaciones Distribuidas Resumen Apuntrix

7. Objetos distribuidos

7.1. Paso de mensajes frente a objetos distribuidos

El paradigma de paso de mensajes es apropiado para los servicios de red, puesto que estosprocesos interactúan a través del intercambio de mensajes. Pero no proporciona la abstracciónnecesaria para algunas aplicaciones de red complejas, por los siguientes motivos:

El paso de mensaje básico requiere que los procesos participantes estén fuertemente aco-plados. Los procesos deben comunicarse directamente entre ellos. Considérese una sesióndel protocolo Echo: si la comunicación entre el cliente y el servidor es interrumpida, lasesión no puede continuar.

El paradigma de paso de mensajes está orientado a datos. Cada mensaje contiene datoscon un formato mutuamente acordado, y se interpreta como una petición o respuesta deacuerdo al protocolo.

El hecho de que el paradigma sea orientado a datos no es adecuado para aplicacionescomplejas que impliquen un gran número de peticiones y respuestas entremezcladas.

El paradigma de objetos distribuidos proporciona mayor abstracción. Este paradigma está ba-sado en objetos existentes en un sistema distribuido. En programación orientada a objetos, éstosse utilizan para representar entidades significativas. Cada objeto encapsula:

El estado o datos de la entidad.

Las operaciones de la entidad.

Un objeto distribuido es aquel cuyos métodos pueden invocarse por un proceso remoto, es decir,un proceso que se ejecuta en un computador conectado a través de una red al computador en elcual se encuentra el objeto. Los recursos de la red se representan como objetos distribuidos. Parasolicitar un servicio de un recurso de red, un proceso invoca uno de sus métodos u operaciones,pasándole los datos como parámetros al método. El método se ejecuta en la máquina remota, yla respuesta es enviada al proceso solicitante como un valor de salida.

7.2. Una arquitectura típica de objetos distribuidos

La premisa de todo sistema de objetos distribuidos es minimizar las diferencias de programa-ción entre las invocaciones de métodos remotos y las llamadas a métodos locales. Deben tratarseaspectos tales como el empaquetamiento de los datos (marshaling), así como la sincronización delos eventos. Estas diferencias quedan ocultas en la arquitectura.

La Figura 18 presenta una arquitectura típica de una utilidad que dé soporte al paradigmade objetos distribuidos.

Figura 18: Un sistema de objetos distribuidos típico.

52

Page 56: Aplicaciones Distribuidas Resumen Apuntrix

Al objeto distribuido proporcionado o exportado por un proceso se le denomina servidor deobjeto. Otra utilidad, denominada registro de objetos, o simplemente registro, debe existir enla arquitectura para registrar los objetos distribuidos.

Para acceder a un objeto distribuido, un proceso, el cliente de objeto, busca en el registropara encontrar una referencia al objeto. El cliente de objeto utiliza esta referencia para reali-zar llamadas a los métodos del objeto remoto, o métodos remotos. Un componente softwarese encarga de gestionar esta llamada, denominado proxy de cliente, y se encarga también deinteractuar con el software en la máquina cliente con el fin de proporcionar soporte en tiempode ejecución para el sistema de objetos distribuidos.

Una arquitectura similar es necesaria en la parte del servidor, donde el soporte en tiempode ejecución para el sistema de objetos distribuidos gestiona la recepción de los mensajes y eldesempaquetado de datos, enviando la llamada a un componente software denominado proxyde servidor. El proxy de servidor invoca la llamada al método local en el objeto distribuido,pasándole los datos desempaquetados como argumentos. El resultado de la ejecución del métodoes empaquetado y enviado por el proxy de servidor al proxy de cliente.

7.3. Sistemas de objetos distribuidos

Entre las herramientas más conocidas se encuentran:

Java RMI

Sistemas basados en CORBA

El modelo de objetos de componentes distribuidos DCOM

Herramientas y API para el protocolo SOAP

Familiarizarse con el API de Java RMI proporciona los fundamentos y prepara al lector paraaprender los detalles de utilidades similares.

7.4. Llamadas a procedimientos remotos

RMI tiene su origen en un paradigma denominado Llamada a procedimientos remotos oRPC.

La programación procedimental precede a la programación orientada a objetos. La llamadaa un procedimiento convencional (no remoto) es una llamada a un procedimiento que reside enel mismo sistema que el que la invoca y por tanto, se denomina llamada a procedimiento local.

Basándose en el modelo RPC, han aparecido un gran número de interfaces de programaciónde aplicaciones. Para enmascarar los detalles de la comunicación entre procesos, cada llamada aprocedimiento remoto se transforma mediante una herramienta denominada rpcgen en una lla-mada a procedimiento local dirigida a un módulo software comúnmente denominado resguardo(stub) o, más formalmente, proxy. Los mensajes que representan la llamada al procedimiento ysus argumentos se pasan a la máquina remota a través del proxy.

Hay que destacar que hay que emplear un proxy a cada lado de la comunicación para pro-porcionar el soporte en tiempo de ejecución necesario para la comunicación entre procesos,llevándose a cabo el correspondiente empaquetado y desempaquetado de datos, así como lasllamadas a sockets necesarias.

7.5. RMI (Remote Method Invocation)

RMI es una implementación orientada a objetos del modelo de llamada a procedimientosremotos. Se trata de una API exclusiva de Java.

En RMI, un servidor de objeto exporta un objeto remoto y lo registra en un servicio dedirectorios. El objeto proporciona métodos remotos, que pueden invocar los programas clientes.

Un objeto remoto se declara como una interfaz remota, una extensión de la interfaz Java. Elservidor de objeto implementa la interfaz remota. Un cliente de objeto accede al objeto mediantela invocación de sus métodos, utilizando una sintaxis similar a las invocaciones de los métodoslocales.

53

Page 57: Aplicaciones Distribuidas Resumen Apuntrix

7.6. La arquitectura de Java RMI

La Figura 19 muestra la arquitectura del API de Java RMI. Al igual que las API de RPC, RMIutiliza módulos de software proxy para dar el soporte en tiempo de ejecución necesario paratransformar la invocación del método remoto en una llamada a un método local y gestionarlos detalles de la comunicación entre procesos subyacente. Cada uno de los extremos de laarquitectura está formado por tres capas de abstracción, que veremos a continuación.

Figura 19: La arquitectura de Java RMI.

Parte cliente de la arquitectura

1. La capa resguardo o stub. La invocación de un método remoto por parte de un procesocliente es dirigida a un objeto proxy, conocido como resguardo, Esta capa se encuentradebajo de la capa de aplicación y sirve para interceptar las invocaciones de los métodosremotos hechas por los programas clientes; una vez interceptada la invocación es enviadaa la capa de referencia remota.

2. La capa de referencia remota interpreta y gestiona las referencias a los objetos de servicioremoto hechas por los clientes, e invoca las operaciones entre procesos de la capa siguiente.

3. La capa de transporte está basada en TCP y por lo tanto es orientada a conexión. Esta capay el resto de la arquitectura se encargan de la conexión entre procesos, transmitiendo losdatos que representan la llamada al método a la máquina remota.

Parte servidora de la arquitectura

1. La capa esqueleto o skeleton se encuentra justo debajo de la capa de aplicación y se utilizapara interactuar con la capa resguardo en la parte cliente.

2. La capa de referencia remota. Esta capa gestiona y transforma la referencia remota origi-nada por el cliente en una referencia local, que es capaz de comprender la capa esqueleto.

3. La capa de transporte. Al igual que en la parte cliente, se trata de una capa de transporteorientada a conexión, es decir, TCP.

Registro de los objetos

El API de RMI hace posible el uso de diferentes servicios de directorios para registrar unobjeto distribuido. Uno de estos servicios de directorios es la interfaz de nombrado y directoriosde Java (JNDI). El registro RMI, rmiregistry, es un servicio de directorios sencillo proporcionadopor el kit de desarrollo de software Java (SDK). El registro RMI es un servicio cuyo servidor,

54

Page 58: Aplicaciones Distribuidas Resumen Apuntrix

cuando está activo, se ejecuta en la máquina del servidor del objeto. Por convención, utiliza elpuerto TCP 1099 por defecto.

Físicamente, las invocaciones del método remoto se transforman en llamadas a los resguardosy esqueletos en tiempo de ejecución, dando lugar a la transmisión de datos a través de la red. LaFigura 20 es un diagrama de tiempos y eventos que describe la interacción entre el resguardo yel esqueleto.

Figura 20: Interacciones entre el resguardo RMI y el esqueleto RMI.

7.7. API de Java RMI

Esta sección cubre las siguientes áreas del API de Java RMI: la interfaz remota, el softwarede la parte servidora y el software de la parte cliente.

La interfaz remota

El punto inicial para crear un objeto distribuido es una interfaz remota Java. Una interfazremota es una interfaz que hereda de la clase Java remote, que permite implementar la interfazutilizando sintaxis RMI. Aparte de la extensión que se hace de la clase remote y de que todaslas declaraciones de los métodos deben especificar la excepción RemoteException, una interfazremota utiliza la misma sintaxis que una interfaz Java local. El Listado 37 muestra un ejemplode interfaz remota.

Listado 37: Un ejemplo de interfaz remota Java.

1 import java.rmi.*;2

3 public interface InterfazEjemplo extends Remote {4

5 public String metodoEj1() throws java.rmi.RemoteException;6

7 public int metodoEj2(float parametro) throws java.rmi.RemoteException;8 }

Obsérvese que un objeto serializable, tal como un objeto String o un objeto de otra clase, puedeser un argumento o puede ser devuelto por un método remoto. Al método remoto se le pasauna copia del elemento, sea éste un tipo primitivo o un objeto. El valor devuelto se gestiona dela misma forma, pero en la dirección contraria.

55

Page 59: Aplicaciones Distribuidas Resumen Apuntrix

Software de la parte servidora

Un servidor de objeto es un objeto que proporciona los métodos y la interfaz de un objetodistribuido. Cada servidor de objeto debe (1) implementar cada uno de los métodos remotosespecificados en la interfaz, y (2) registrar en un servicio de directorios un objeto que contienela implementación. Se recomienda que las dos partes se realicen en clases separadas.

La implementación de la interfaz remota Se debe crear una clase que implemente la interfazremota. El Listado 38 muestra un esquema de la implementación.

Listado 38: Sintaxis de un ejemplo de implementación de interfaz remota.

1 import java.rmi.*;2 import java.rmi.server.*;3 /**4 * Esta clase implementa InterfazEjemplo.5 */6 public class ImplEjemplo extends UnicastRemoteObject implements InterfazEjemplo {7

8 public ImplEjemplo() throws RemoteException {9 super();

10 }11

12 public String metodoEj1() throws RemoteException {13 //Código del método14 }15

16 public int metodoEj2(float parametro) {17 //Código del método18 }19 }

Generación del resguardo y del esqueleto En RMI un objeto distribuido requiere un proxypor cada uno de los servidores y clientes de objeto, conocidos como esqueleto y resguardo delobjeto, respectivamente. Estos proxies se generan a partir de la implementación de una interfazremota utilizando una herramienta del SDK de Java: el compilador RMI rmic. Para utilizar estaherramienta, se debe ejecutar el siguiente comando:

rmic ImplEjemplo

Si la compilación se realiza con éxito, se generan dos ficheros proxy, por ejemplo ImplEjem-plo_skel.class y ImplEjemplo_stub.class. Estos ficheros son imprescindibles para que el programacliente pueda compilar correctamente. Una copia de cada fichero debe colocarse manualmenteen la parte cliente.

El servidor de objeto La clase del servidor de objeto instancia y exporta un objeto de la imple-mentación de la interfaz remota. El Listado 39 muestra una plantilla para la clase del servidorde objeto.

Listado 39: Sintaxis de un ejemplo de un servidor de objeto.

1 import java.rmi.*;2 import java.rmi.server.*;3 import java.rmi.registry.Registry;4 import java.rmi.registry.LocateRegistry;5 import java.net.*;6 import java.io.*;7

8 /**9 * Clase que representa el servidor de un objeto distribuido de la clase

10 * ImplEjemplo, que implementa la interfaz remota InterfazEjemplo.11 */12 public class ServidorEjemplo {13

14 public static void main (String[] args) {

56

Page 60: Aplicaciones Distribuidas Resumen Apuntrix

15 String numPuertoRMI, URLRegistro;16 try {17 ImplEjemplo objExportado = new ImplEjemplo();18 arrancarRegistro(numPuertoRMI);19 URLRegistro = "rmi://localhost:" + numPuerto + "/ejemplo";20 Naming.rebind(URLRegistro, objExportado);21 System.out.println("Servidor preparado");22 } //fin try23 catch (Exception e) {24 e.printStackTrace();25 }26 } //fin main27

28 private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {29 try {30 Registry registro = LocateRegistry.getRegistry(numPuertoRMI);31 registro.list(); //lanza excepción si no existe32 } //fin try33 catch (Exception e) {34 System.out.println("El registro RMI no se puede localizar en el puerto: " +

numPuertoRMI);35 Registry registro = LocateRegistry.createRegistry(numPuertoRMI);36 System.out.println("Registro RMI creado en el puerto: " + numPuertoRMI);37 } //fin catch38 } //fin arrancarRegistro39

40 } //fin class

Analicemos las diferentes partes de esta plantilla.Creación de un objeto de la implementación de la interfaz remota. En la línea 17 se crea un

objeto de la clase que implementa la interfaz remota; a continuación se exportará la referencia aeste objeto.

Exportación del objeto. Las líneas 19-21 exportan el objeto. Se debe registrar su referenciaen un servicio de directorios. En este capítulo utilizaremos el servicio rmiregistry, el cual debeejecutarse en el nodo del servidor de objeto para poder registrar objetos RMI.

En la plantilla del servidor de objeto, se implementa el método estático arrancarRegistro()(líneas 28-38), que arranca un servidor de registro RMI si no está actualmente en ejecución, enun número de puerto especificado por el usuario.

En el código para exportar un objeto (líneas 19-20), la clase Naming proporciona métodos paraalmacenar y obtener referencias del registro. En particular, el método rebind permite almacenaren el registro una referencia a un objeto con un URL de la forma:

rmi://<nombre máquina>:<número puerto>/<nombre referencia>

El método rebind sobreescribe cualquier referencia en el registro asociada al nombre de la refe-rencia. Si no se desea sobrescribir, existe un método denominado bind.

Cuando se ejecuta un servidor de objeto, la exportación de los objetos distribuidos provocaque el proceso servidor comience a escuchar por el puerto y espere a que los clientes se conecteny soliciten el servicio del objeto. Un servidor de objeto RMI es un servidor concurrente.

Software de la parte cliente

Es como cualquier otra clase Java. La sintaxis necesaria para hacer uso de RMI supone locali-zar el registro RMI en el nodo servidor y buscar la referencia remota para el servidor de objeto;a continuación se realizará un cast de la referencia a la clase de la interfaz remota y se invocaránlos métodos remotos. El Listado 40 presenta una plantilla para el cliente de objeto.

Listado 40: Plantilla para un cliente de objeto.

1 import java.io.*;2 import java.rmi.*;3 import java.rmi.registry.Registry;4 import java.rmi.registry.LocateRegistry;5

6 /**7 * Clase que representa el cliente de un objeto distribuido de la8 * clase ImplEjemplo, que implementa la interfaz remota InterfazEjemplo.

57

Page 61: Aplicaciones Distribuidas Resumen Apuntrix

9 */10

11 public class ClienteEjemplo {12 public static void main (String[] args) {13 try {14 int puertoRMI;15 String nombreNodo;16 String numPuerto;17 String URLRegistro = "rmi://localhost:" + numPuerto + "/ejemplo";18 InterfazEjemplo h = (InterfazEjemplo)Naming.lookup(URLRegistro);19 String mensaje = h.metodoEj1();20 System.out.println(mensaje);21 } //fin try22 catch (Exception e) {23 e.printStackTrace();24 }25 } //fin main26 } //fin class

7.8. Una aplicación RMI de ejemplo

En los Listados 41 a 44 se muestran los ficheros necesarios para crear la aplicación RMIHolaMundo. El servidor exporta un objeto que contiene un único método, denominado decirHola.

Listado 41: HolaMundoInt.java

1 import java.rmi.*;2

3 /**4 * Interfaz remota.5 */6

7 public interface HolaMundoInt extends Remote {8 /**9 * Devuelve un mensaje.

10 * @param name - Una cadena de caracteres con un nombre11 * @return - Una cadena de caracteres.12 */13 public String decirHola(String nombre) throws java.rmi.RemoteException;14 }

Listado 42: HolaMundoImpl.java

1 import java.rmi.*;2 import java.rmi.server.*;3

4 /**5 * Implementación de la interfaz remota.6 */7

8 public class HolaMundoImpl extends UnicastRemoteObjetc implements HolaMundoInt {9

10 public HolaMundoImpl() throws RemoteException {11 super();12 }13

14 public String decirHola(String nombre) throws RemoteException {15 return "Hola mundo! " + nombre;16 }17 }

Listado 43: HolaMundoServidor.java

1 import java.io.*;2 import java.net.*;3 import java.rmi.*;4 import java.rmi.server.*;5 import java.rmi.registry.Registry;

58

Page 62: Aplicaciones Distribuidas Resumen Apuntrix

6 import java.rmi.registry.LocateRegistry;7

8 /**9 * Clase que representa el servidor de un objeto de la clase HolaMundo,

10 * que implementa la interfaz remota HolaMundoInt.11 */12 public class HolaMundoServidor {13

14 public static void main (String[] args) {15 InputStreamReader ent = new InputStreamReader(System.in);16 BufferedReader buf = new BufferedReader(ent);17 String numPuerto, URLRegistro;18 try {19 System.out.println("Introducir el número de puerto del registro RMI:");20 numPuerto = buf.readLine().trim();21 int numPuertoRMI = Integer.parseInt(numPuerto);22 arrancarRegistro(numPuertoRMI);23

24 HolaMundoImpl objExportado = new HolaMundoImpl();25 URLRegistro = "rmi://localhost:" + numPuerto + "/holaMundo";26 Naming.rebind(URLRegistro, objExportado);27 System.out.println("Servidor registrado. El registro contiene actualmente:")

;28 listarRegistro(URLRegistro);29

30 System.out.println("Servidor Hola Mundo preparado");31 } //fin try32 catch (Exception e) {33 e.printStackTrace();34 }35 } //fin main36

37 /**38 * Arrancar un registro RMI en la máquina local, si es posible.39 */40 private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {41 try {42 Registry registro = LocateRegistry.getRegistry(numPuertoRMI);43 registro.list(); //lanza excepción si no existe44 } //fin try45 catch (RemoteException e) {46 System.out.println("El registro RMI no se localiza en el puerto " +

numPuertoRMI);47 Registry registro = LocateRegistry.createRegistry(numPuertoRMI);48 System.out.println("Registro RMI creado en el puerto " + numPuertoRMI);49 } //fin catch50 } //fin arrancarRegistro51

52 /**53 * Listar los nombres registrados con un objeto Registry54 */55 private static void listarRegistro(String URLRegistro) throws RemoteException,

MalformedURLException {56 System.out.println("Registro " + URLRegistro + " contiene: ");57 String[] nombres = Naming.list(URLRegistro);58 for (int i = 0; i<nombres.length; i++)59 System.out.println(nombres[i]);60 } //fin listaRegistro61

62 } //fin class

Listado 44: HolaMundoCliente.java

1 import java.io.*;2 import java.rmi.*;3

4 /**5 * Clase que representa el cliente de un objeto distribuido de clase HolaMundo,6 * que implementa la interfaz remota HolaMundoInt.7 */8 public class HolaMundoCliente {9 public static void main (String[] args) {

59

Page 63: Aplicaciones Distribuidas Resumen Apuntrix

10 try {11 int numPuertoRMI;12 String nombreNodo;13 InputStreamReader ent = new InputStreamReader(System.in);14 BufferedReader buf = new BufferedReader(ent);15 System.out.println("Introducir el nombre del nodo del registro RMI:");16 nombreNodo = buf.readLine();17 System.out.println("Inroducir el número de puerto del registro RMI:");18 String numPuerto = buf.readLine();19 numPuertoRMI = Integer.parseInt(numPuerto);20 String URLRegistro = "rmi://" + nombreNodo + ":" + numPuerto + "/holaMundo";21

22 //Buscar objeto remoto23 HolaMundoInterfaz h = (HolaMundoInterfaz)Naming.lookup(URLRegistro);24 System.out.println("Búsqueda completa");25

26 //Invocar método remoto27 String mensaje = h.decirHola("Pato Donald");28 System.out.println("HolaMundoCliente: " + mensaje);29 } //fin try30 catch (Exception e) {31 e.printStackTrace();32 }33 } //fin main34 } //fin class

7.9. Pasos para construir una aplicación RMI

Se va a describir paso a paso el procedimiento para construir una aplicación RMI. Se describetanto la parte del servidor de objeto como del cliente de objeto. El algoritmo es expresado entérminos de una aplicación denominada Ejemplo.

Algoritmo para desarrollar el software de la parte servidora

1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicación.

2. Especificar la interfaz remota del servidor en InterfazEjemplo.java. Compilarla y revisarla.

3. Implementar la interfaz en ImplEjemplo.java. Compilarla y revisarla.

4. Utilizar el compilador de RMI rmic para procesar la clase de la implementación y generarlos ficheros de resguardo y esqueleto para el objeto remoto:

rmic ImplEjemplo

Los ficheros generados se encontrarán en el directorio como ImplEjemplo_Stub.class e Im-plEjemplo_Skel.class. Se deben repetir los pasos 3 y 4 cada vez que se realice un cambio a laimplementación de la interfaz.

5. Crear el programa del servidor de objeto ServidorEjemplo.java. Compilarlo y revisarlo.

6. Activar el servidor de objeto.

java ServidorEjemplo

Algoritmo para desarrollar el software de la parte cliente

1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicación.

2. Obtener una copia del fichero class (compilado) de la interfaz remota.

3. Obtener una copia del fichero de resguardo para la implementación de la interfaz, ImplE-jemplo_Stub.class.

4. Desarrollar el programa cliente ClienteEjemplo.java. Compilarlo y revisarlo.

5. Activar el cliente.

java ClienteEjemplo

60

Page 64: Aplicaciones Distribuidas Resumen Apuntrix

7.10. Pruebas y depuración

Es recomendable utilizar los siguientes pasos incrementales a la hora de desarrollar unaaplicación RMI:

1. Construir una plantilla para un programa RMI básico. Empezar con una interfaz remotaque sólo contenga la declaración de un método, su implementación utilizando un resguar-do, un programa servidor que exporte el objeto y un programa cliente con código que sóloinvoque al método remoto.

2. Añadir una declaración cada vez a la interfaz. Con cada adición, modificar el programacliente para que invoque al método que se ha añadido.

3. Rellenar la definición de cada método remoto uno a uno. Probar y depurar de formadetallada cada método antes de incluir el siguiente.

4. Después de que todos los métodos remotos se han probado detalladamente, crear la apli-cación cliente utilizando una técnica incremental.

5. Distribuir los programas en máquinas separadas. Probarlos y depurarlos.

7.11. Comparación entre RMI y el API de sockets

El API de RMI es una herramienta eficiente para construir aplicaciones de red. Puede utili-zarse en lugar del API de sockets para construir una aplicación de red rápidamente. Además deventajas, también existen desventajas en esta opción:

1. El API de sockets está más cercano al sistema operativo, por lo que tiene menos sobrecargade ejecución. RMI requiere soporte software adicional (proxies y el servicio de directorio)que implican una sobrecarga en tiempo de ejecución.

2. El API de RMI proporciona la abstracción necesaria para facilitar el desarrollo de software.Los programas desarrollados en RMI son más comprensibles y por tanto más sencillos dedepurar.

3. El API de sockets se trata de una API típicamente independiente de plataforma y lenguaje.Java RMI requiere soportes de tiempo de ejecución específicos de Java. Una aplicación JavaRMI debe escribirse en Java y sólo se puede ejecutar en plataformas Java.

61

Page 65: Aplicaciones Distribuidas Resumen Apuntrix

8. RMI avanzado

Este capítulo analizará algunas de las características avanzadas de RMI más interesantes, asaber, descarga de resguardo, gestores de seguridad y callback de cliente. Se trata de mecanis-mos que pueden ser útiles para los desarrolladores de aplicaciones. El estudio de estos temaspermite reforzar el conocimiento del paradigma de objetos distribuidos en general.

8.1. Callback de cliente

Considérese una aplicación RMI donde un servidor de objeto debe notificar a los procesosparticipantes la ocurrencia de algún evento. Dentro del entorno del API básica de RMI pre-sentada en el capítulo anterior, es imposible que el servidor inicie una llamada al cliente paratransmitirle alguna clase de información, debido a que una llamada a método remoto es unidi-reccional. Una forma de llevar a cabo la transmisión de información es que cada proceso clienterealice un sondeo al servidor de objeto, invocando de forma repetida un método remoto.

El sondeo (polling) se trata de una técnica muy costosa en términos de recursos del sistema.Una técnica más eficiente se denomina callback: permite que cada cliente de objeto interesadoen la ocurrencia de un evento se registre a sí mismo con el servidor de objeto, de forma que elservidor inicie una invocación de un método remoto del cliente de objeto cuando dicho eventoocurra.

En RMI, el callback de cliente es una característica que permite a un cliente de objeto re-gistrarse a sí mismo con un servidor de objeto remoto para callbacks, de forma que el servidorpueda llevar a cabo una invocación del método del cliente cuando el evento ocurra. Las invoca-ciones de los métodos remotos se convierten en bidireccionales, o dúplex. Se necesita claramentesintaxis adicional para dar soporte a esta nueva característica.

Cuando un servidor de objeto realiza un callback, los papeles de los dos procesos se invier-ten: el servidor de objeto se convierte en cliente del cliente de objeto. La Figura 21 muestra laarquitectura de RMI con callback de cliente. Se puede observar que en este caso se necesitan dosconjuntos de proxies. La interfaz remota del cliente proporciona un método remoto que puedeinvocar el servidor a través del callback.

Figura 21: La arquitectura de RMI con callback de cliente.

Como ejemplo, se extenderá la aplicación HolaMundo de forma que el cliente del objeto seregistre con el servidor para callback y entonces se le notifique de cualquier registro de otrocliente de objeto para callback con el servidor.

62

Page 66: Aplicaciones Distribuidas Resumen Apuntrix

Extensión de la parte cliente para callback de cliente

Para el callback, el cliente debe proporcionar un método remoto que permita al servidornotificarle el evento correspondiente.

La interfaz remota de clienteEl servidor de objeto proporciona una interfaz remota que declara los métodos que un clientede objeto puede invocar. Para el callback, es necesario que el cliente de objeto proporcione unainterfaz remota similar. Se le denominará interfaz remota de cliente (InterfazCallbackCliente). Lainterfaz remota de cliente debe contener al menos un método que será invocado por el servidoren el callback. Como ejemplo:

public interface InterfazCallbackCliente extends java.rmi.Remote {

public String notificame(String mensaje) throws java.rmi.RemoteException;

}

El servidor debe invocar el método notificame cuando realiza el callback, pasando como argu-mento una cadena de caracteres. Una vez recibido el callback, el cliente compone otra cadena decaracteres que devuelve al servidor.

La implementación de la interfaz remota de clienteEs necesario implementar la interfaz remota de cliente en una clase (ImplCallbackCliente), tal ycomo se muestra a continuación:

import java.rmi.*;import java.rmi.server.*;

public class ImplCallbackCliente extends UnicastRemoteObject implementsInterfazCallbackCliente {

public ImplCallbackCliente() throws RemoteException {super();

}

public String notificame(String mensaje) {String mensajeRet = "Callback recibido: " + mensaje;System.out.println(mensajeRet);return mensajeRet;

}

}

Al igual que la interfaz remota de servidor, se debe utilizar el compilador rmic con la im-plementación de la interfaz remota de cliente para generar los proxies necesarios en tiempo deejecución.

Extensión de la clase clienteSe necesita añadir código al cliente para que instancie un objeto de la implementación de lainterfaz remota de cliente. A continuación, se registra con el servidor una referencia al objetoutilizando un método remoto proporcionado por el servidor. Un ejemplo de cómo debe realizar-se esto es:

InterfazCallbackServidor h = (InterfazCallbackServidor)Naming.lookup(URLRegistro);InterfazCallbackCliente objCallback = new InterfazCallbackCliente();h.registrarCallback(objCallback);

Los listados 45 a 47 presentan el código del software de la parte cliente para la aplicaciónHolaMundo modificada.

Listado 45: Fichero InterfazCallbackCliente.java de la aplicación HolaMundo modificada.

1 import java.rmi.*;2

3 /**4 * Interfaz remota para ilustrar el callback de cliente.

63

Page 67: Aplicaciones Distribuidas Resumen Apuntrix

5 */6 public interface InterfazCallbackCliente extends java.rmi.Remote {7

8 /**9 * @param mensaje - Cadena de caracteres que contiene información procesada por

10 * el cliente.11 */12 public String notificame(String mensaje) throws java.rmi.RemoteException;13

14 }

Listado 46: Fichero ImplCallbackCliente.java de la aplicación HolaMundo modificada.

1 import java.rmi.*;2 import java.rmi.server.*;3

4 /**5 * Clase que implementa la interfaz remota InterfazCallbackCliente.6 */7 public class ImplCallbackCliente extends UnicastRemoteObject implements

InterfazCallbackCliente {8

9 public ImplCallbackCliente() throws RemoteException {10 super();11 }12

13 public String notificame(String mensaje) {14 String mensajeRet = "Callback recibido: " + mensaje;15 System.out.println(mensajeRet);16 return mensajeRet;17 }18

19 }

Listado 47: Fichero ClienteEjemplo.java de la aplicación HolaMundo modificada.

1 import java.io.*;2 import java.rmi.*;3

4 /**5 * Clase que representa el cliente de objeto para un objeto distribuido6 * de la clase ImplCallbackServidor, que implementa la interfaz remota7 * InterfazCallbackServidor. También acepta callbacks del servidor.8 */9 public class ClienteEjemplo {

10 public static void main(String[] args) {11 try {12 int puertoRMI;13 String nombreNodo;14 InputStreamReader ent = new InputStreamReader(System.in);15 BufferedReader buf = new BufferedReaedr(ent);16

17 System.out.println("Introduce el nombre de nodo del registro RMI:");18 nombreNodo = buf.readLine();19 System.out.println("Introduce el número de puerto del registro RMI:");20 String numPuerto = buf.readLine();21 puertoRMI = Integer.parseInt(numPuerto);22 System.out.println("Introduce cuántos segundos va a permanecer registrado:")

;23 String duracionTiempo = buf.readLine();24 int tiempo = Integer.parseInt(duracionTiempo);25 String URLRegistro = "rmi://localhost:" + numPuerto + "/callback";26

27 //Buscar objeto remoto y cast28 InterfazCallbackServidor h = (InterfazCallbackServidor)Naming.lookup(

URLRegistro);29 System.out.println("Búsqueda completa.");30 System.out.println("El servidor dice " + h.decirHola());31

32 InterfazCallbackCliente objCallback = new ImplCallbackCliente();33 h.registrarCallback(objCallback);

64

Page 68: Aplicaciones Distribuidas Resumen Apuntrix

34 System.out.println("Registrado para callback");35

36 try {37 thread.sleep(tiempo*1000);38 }39 catch (InterruptedException e) {40 h.eliminarRegistroCallback(objCallback);41 System.out.println("No registrado para callback");42 }43 } //fin try44 catch (Exception e) {45 System.out.println("Excepción en ClienteEjemplo: " + e);46 }47 } //fin main48 } //fin class

Extensión de la parte servidora para callback de cliente

En la parte del servidor, se necesita añadir un método remoto para que el cliente puedaregistrarse para callback. En el caso más sencillo, la cabecera del método puede ser análoga a:

public void registrarCallback (InterfazCallbackCliente objCallbackCliente) throwsjava.rmi.RemoteException;

La implementación de estos métodos, así como la implementación de un método local hacer-Callbacks se muestra en el Listado 49. El Listado 48 muestra el fichero con la interfaz del servidor.El Listado 50 muestra el código para el servidor de objeto, que queda sin modificar con respectoa la anterior versión.

Listado 48: Fichero InterfazCallbackServidor.java de la aplicación HolaMundo modificada.

1 import java.rmi.*;2

3 /**4 * Interfaz remota para ilustrar el callback de cliente.5 */6 public interface InterfazCallbackServidor extends Remote {7

8 public String decirHola() throws java.rmi.RemoteException;9

10 /**11 * @param objClienteCallback - referencia al cliente de objeto; el servidor lo12 * utiliza para realizar los callbacks.13 */14 public void registrarCallback(InterfazCallbackCliente objCallbackCliente) throws

java.rmi.RemoteException;15

16 public void eliminarRegistroCallback(InterfazCallbackCliente objCallbackCliente)throws java.rmi.RemoteException;

17

18 }

Listado 49: Fichero ImplCallbackServidor.java de la aplicación HolaMundo modificada.

1 import java.rmi.*;2 import java.rmi.server.*;3 import java.util.Vector;4

5 /**6 * Clase que implementa la interfaz remota.7 */8 public class ImplCallbackServidor extends UnicastRemoteObject implements

InterfazCallbackServidor {9 private vector listaClientes;

10

11 public ImplCallbackServidor() throws RemoteException {12 super();13 listaClientes = new Vector();14 }

65

Page 69: Aplicaciones Distribuidas Resumen Apuntrix

15

16 public String decirHola() throws RemoteException {17 return("Hola mundo");18 }19

20 public void registrarCallback(InterfazCallbackCliente objCallbackCliente) throwsRemoteException {

21 if(!(listaClientes.contains(objCallbackCliente))) {22 listaClientes.addElement(objCallbackCliente);23 System.out.println("Nuevo cliente registrado");24 hacerCallbacks();25 }26 }27

28 public synchronized void eliminarRegistroCallback(InterfazCallbackClienteobjCallbackCliente) throws RemoteException {

29 if(listaClientes.removeElement(objCallbackCliente)) {30 System.out.println("Cliente no registrado");31 } else {32 System.out.println("eliminarRegistroCallback: el cliente no fue registrado")

;33 }34 }35

36 private synchronized void hacerCallbacks() throws RemoteException {37 System.out.println("*******************************************\nCallback

iniciado -- ");38 for(int i = 0; i<listaClientes.size(); i++) {39 System.out.println("Haciendo callback número " + i + "\n");40 InterfazCallbackCliente proxCliente = (InterfazCallbackCliente)listaClientes

.elementAt(i);41 proxCliente.notificame("Número de clientes registrados=" + listaClientes.

size());42 }43 System.out.println("*******************************************\nServidor

completó callbacks -- ");44 }45

46 } //fin class

Listado 50: Fichero ServidorEjemplo.java de la aplicación HolaMundo modificada.

1 import java.rmi.*;2 import java.rmi.server.*;3 import java.rmi.registry.Registry;4 import java.rmi.registry.LocateRegistry;5 import java.net.*;6 import java.io.*;7

8 /**9 * Clase que representa el servidor de un objeto distribuido de la clase

10 * Callback, que implementa la interfaz remota InterfazCallback.11 */12 public class ServidorEjemplo {13

14 public static void main (String[] args) {15 InputStreamReader ent = new InputStreamReader(System.in);16 BufferedReader buf = new BufferedReader(ent);17 String numPuerto, URLRegistro;18 try {19 System.out.println("Introducir el número de puerto del registro RMI:");20 numPuerto = (buf.readLine()).trim();21 int numPuertoRMI = Integer.parseInt(numPuerto);22 arrancarRegistro(numPuertoRMI);23

24 ImplCallbackServidor objExportado = new ImplCallbackServidor();25 URLRegistro = "rmi://localhost:" + numPuerto + "/callback";26 Naming.rebind(URLRegistro, objExportado);27 System.out.println("Servidor callback preparado");28 }29 catch (Exception e) {30 System.out.println("Excepción en ServidorEjemplo.main: " + e);

66

Page 70: Aplicaciones Distribuidas Resumen Apuntrix

31 }32 } //fin main33

34 private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {35 try {36 Registry registro = LocateRegistry.getRegistry(numPuertoRMI);37 registro.list(); //lanza excepción si no existe38 }39 catch (Exception e) {40 System.out.println("El registro RMI no se puede localizar en el puerto: " +

numPuertoRMI);41 Registry registro = LocateRegistry.createRegistry(numPuertoRMI);42 System.out.println("Registro RMI creado en el puerto: " + numPuertoRMI);43 }44 } //fin arrancarRegistro45

46 } //fin class

Pasos para construir una aplicación RMI con callback de cliente

Algoritmo para desarrollar el software de la parte del servidor

1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicación.

2. Especificar la interfaz remota del servidor en InterfazCallbackServidor.java. Compilarla y eje-cutarla.

3. Implementar la interfaz en ImplCallbackServidor.java. Compilarla y revisarla.

4. Utilizar el compilador RMI rmic para procesar la clase de la implmentación y generar losficheros resguardo y esqueleto para el objeto remoto:

rmic ImplCallbackServidor

Los pasos 3 y 4 deben repetirse cada vez que se cambie la implementación de la interfaz.

5. Obtener una copia del fichero class de la interfaz remota del cliente.

6. Crear el programa correspondiente al servidor de objeto ServidorEjemplo.java. Compilarloy revisarlo.

7. Obtener una copia del fichero resguardo de la interfaz de la interfaz remota del clienteImplCallbackCliente_Stub.class.

8. Activar el servidor de objeto

java ServidorEjemplo

Algoritmo para desarrollar el software de la parte cliente

1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicación.

2. Especificar la interfaz remota de cliente en InterfazCallbackCliente.java. Compilarla y revi-sarla.

3. Implementar la interfaz en ImplCallbackCliente.java. Compilarla y revisarla.

4. Utilizar el compilador RMI rmic para procesar la clase de la implementación ImplCallback-Cliente.class y generar los ficheros resguardo y esqueleto para el objeto remoto:

rmic ImplCallbackCliente

Los pasos 3 y 4 deben repetirse cada vez que se cambie la implementación de la interfaz.

5. Obtener una copia del fichero class de la interfaz remota del servidor.

67

Page 71: Aplicaciones Distribuidas Resumen Apuntrix

6. Crear el programa correspondiente al cliente de objeto ClienteEjemplo.java. Compilarlo yrevisarlo.

7. Obtener una copia del fichero resguardo de la interfaz remota del servidor ImplCallback-Servidor_Stub.class.

8. Activar el cliente de objeto

java ClienteEjemplo

8.2. Descarga de resguardo

Java RMI proporciona un mecanismo que permite que los clientes obtengan dinámicamentelos resguardos necesarios. Mediante descarga dinámica de resguardo, no se necesita una copiade la clase del resguardo en la máquina cliente. Por el contrario, éste se transmite bajo demandadesde un servidor web a la máquina cliente cuando se activa dicho cliente.

Mediante el uso de descarga dinámica, el desarrollador almacena una clase resguardo en unservidor web como un documento web, que puede ser descargado (utilizando HTTP) cuandoun cliente de objeto se ejecuta, de la misma forma que se lleva a cabo la descarga de applets.

La clase resguardo descargada no es persistente, es decir, no se almacena de forma perma-nente en la máquina cliente, sino que por el contrario el sistema libera la clase correspondientecuando la sesión del cliente finaliza.

8.3. El gestor de seguridad de RMI

La descarga de resguardo supone un problema para el sistema de seguridad. Cuando unobjeto como un resguardo RMI se transfiere desde un nodo remoto, su ejecución entraña elriesgo de ataques maliciosos al nodo local.

Java proporciona una clase denominada RMISecurityManager. Un programa RMI puede ins-tanciar un objeto de esta clase. Una vez instanciado, el objeto supervisa durante la ejecucióndel programa todas las acciones que puedan suponer un riesgo de seguridad. En particular, elsoporte en tiempo real de RMI requiere que un proceso servidor instale un gestor de seguridadantes de exportar cualquier objeto que requiera descarga de resguardo, y que un cliente instaleun gestor de seguridad antes de que pueda realizar la descarga del resguardo.

Aunque la noción de gestor de seguridad no se introdujo en el capítulo anterior, se recomienda suuso en todas las aplicaciones RMI, independientemente de que se utilice descarga de resguardo o no.Por defecto, un gestor de seguridad RMI es muy restrictivo: no permite acceso a los ficheros ysólo permite conexiones a la máquina origen. Es posible relajar estas condiciones instalando unfichero especial conocido como fichero de política de seguridad, cuya sintaxis especifica el tipode restricción que un gestor de seguridad debe utilizar. Alternativamente, una aplicación puedeespecificar un fichero de políticas de seguridad, de forma que las restricciones las impone lapropia aplicación. Se recomienda que se especifique un fichero de seguridad con cada aplicaciónque se ejecute, de forma que se tenga control exclusivamente sobre las restricciones impuestasen la aplicación que se use, sin afectar a las restricciones de otros programas.

A continuación, se describe cómo una aplicación utiliza el gestor de seguridad de RMI.

Instanciación de un gestor de seguridad en un programa RMI

La clase RMISecurityManager se puede instanciar tanto en el cliente de objeto como en elservidor de objeto utilizando la siguiente sentencia:

System.setSecurityManager(new RMISecurityManager());

Esta sentencia debería aparecer antes del código de acceso al registro RMI. Los Listados 51 y52 muestran los ejemplo del programa HolaMundo, presentados en el capítulo anterior, peroinstanciando un gestor de seguridad.

Listado 51: HolaMundoServidor.java haciendo uso de un gestor de seguridad.

1 import java.io.*;2 import java.net.*;

68

Page 72: Aplicaciones Distribuidas Resumen Apuntrix

3 import java.rmi.*;4 import java.rmi.server.*;5 import java.rmi.registry.Registry;6 import java.rmi.registry.LocateRegistry;7

8 /**9 * Clase que representa el servidor de un objeto de la clase HolaMundo,

10 * que implementa la interfaz remota HolaMundoInt.11 * Se instala un12 */13 public class HolaMundoServidor {14

15 public static void main (String[] args) {16 InputStreamReader ent = new InputStreamReader(System.in);17 BufferedReader buf = new BufferedReader(ent);18 String numPuerto, URLRegistro;19 try {20 System.out.println("Introducir el número de puerto del registro RMI:");21 numPuerto = buf.readLine().trim();22 int numPuertoRMI = Integer.parseInt(numPuerto);23

24 // Arrancar un gestor de seguridad - necesario si se utiliza la25 // descarga de resguardo26 System.setSecurityManager(new RMISecurityManager());27

28 arrancarRegistro(numPuertoRMI);29

30 HolaMundoImpl objExportado = new HolaMundoImpl();31 URLRegistro = "rmi://localhost:" + numPuerto + "/holaMundo";32 Naming.rebind(URLRegistro, objExportado);33 System.out.println("Servidor registrado. El registro contiene actualmente:")

;34 listarRegistro(URLRegistro);35

36 System.out.println("Servidor Hola Mundo preparado");37 } //fin try38 catch (Exception e) {39 e.printStackTrace();40 }41 } //fin main42

43 /**44 * Arrancar un registro RMI en la máquina local, si es posible.45 */46 private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {47 try {48 Registry registro = LocateRegistry.getRegistry(numPuertoRMI);49 registro.list(); //lanza excepción si no existe50 } //fin try51 catch (RemoteException e) {52 System.out.println("El registro RMI no se localiza en el puerto " +

numPuertoRMI);53 Registry registro = LocateRegistry.createRegistry(numPuertoRMI);54 System.out.println("Registro RMI creado en el puerto " + numPuertoRMI);55 } //fin catch56 } //fin arrancarRegistro57

58 /**59 * Listar los nombres registrados con un objeto Registry60 */61 private static void listarRegistro(String URLRegistro) throws RemoteException,

MalformedURLException {62 System.out.println("Registro " + URLRegistro + " contiene: ");63 String[] nombres = Naming.list(URLRegistro);64 for (int i = 0; i<nombres.length; i++)65 System.out.println(nombres[i]);66 } //fin listaRegistro67

68 } //fin class

Listado 52: HolaMundoCliente.java haciendo uso de un gestor de seguridad.

69

Page 73: Aplicaciones Distribuidas Resumen Apuntrix

1 import java.io.*;2 import java.rmi.*;3

4 /**5 * Clase que representa el cliente de un objeto distribuido de clase HolaMundo,6 * que implementa la interfaz remota HolaMundoInt.7 */8 public class HolaMundoCliente {9 public static void main (String[] args) {

10 try {11 int numPuertoRMI;12 String nombreNodo;13 InputStreamReader ent = new InputStreamReader(System.in);14 BufferedReader buf = new BufferedReader(ent);15 System.out.println("Introducir el nombre del nodo del registro RMI:");16 nombreNodo = buf.readLine();17 System.out.println("Inroducir el número de puerto del registro RMI:");18 String numPuerto = buf.readLine();19 numPuertoRMI = Integer.parseInt(numPuerto);20

21 // Arrancar un gestor de seguridad - esto es necesario si se utiliza22 // la descarga de resguardo23 System.setSecurityManager(new RMISecurityManager());24

25 String URLRegistro = "rmi://" + nombreNodo + ":" + numPuerto + "/holaMundo";26

27 //Buscar objeto remoto28 HolaMundoInterfaz h = (HolaMundoInterfaz)Naming.lookup(URLRegistro);29 System.out.println("Búsqueda completa");30

31 //Invocar método remoto32 String mensaje = h.decirHola("Pato Donald");33 System.out.println("HolaMundoCliente: " + mensaje);34 } //fin try35 catch (Exception e) {36 e.printStackTrace();37 }38 } //fin main39 } //fin class

La sintaxis de un fichero de políticas de seguridad de Java

Es un fichero de texto que contiene códigos que permiten especificar la concesión de permisosespecíficos. A continuación se muestra un fichero típico java.policy para una aplicación RMI.

grant {// Este permiso permite a los clientes RMI realizar conexiones de sockets// a los puertos públicos de cualquier computador.// Si se arranca un puerto en el registro RMI en este rango, no existirá// violación de acceso de conexión.permission java.net.SocketPermission "*:1024-65535", "connect,accept,resolve";// Este permiso permite a los sockets acceder al puerto 80, el puerto por// defecto HTTP que el cliente necesita para contactar con el servidor HTTP// para descarga de resguardo.permission java.net.SocketPermission "*:80", "connect";

};

Cuando se realicen los ejercicios, hay que hacer una copia de este fichero para la aplicacióncon el nombre java.policy en el mismo directorio tanto en la máquina del cliente como en lamáquina del servidor de objeto.

Cuando se active el cliente, hay que utilizar la opción del mandato que permite especificarque el proceso cliente debe tener los permisos definidos en el fichero de políticas, de la siguienteforma:

java -Djava.security.policy=java.policy ClienteEjemplo

Del mismo modo, el servidor debe activarse así:

java -Djava.security.policy=java.policy ServidorEjemplo

70

Page 74: Aplicaciones Distribuidas Resumen Apuntrix

Uso de descarga de resguardo y un fichero de políticas de seguridad

1. Si debe descargarse el resguardo de un servidor HTTP, transfiera la clase resguardo aun directorio apropiado del servidor HTTP, y asegúrese de que el permiso de acceso delfichero es de lectura para todos los usuarios.

2. Cuando se activa el servidor, se debe especificar las siguientes opciones del mandato:

java -Djava.rmi.server.codbase=<URL> -Djava.security.policy=<ficherode políticas> <Aplicación Java>

Algoritmos para construir una aplicación RMI, que permite descarga de resguardo

Algoritmo para desarrollar el software de la parte del servidor

1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicación.

2. Especificar la interfaz remota de servidor en InterfazEjemplo.java. Compilarla y revisarla.

3. Implementar la interfaz en ImplEjemplo.java. Compilarla y revisarla.

4. Utilizar el compilador RMI rmic (rmic ImplEjemplo) para procesar la clase de la imple-mentación y generar los ficheros resguardo y esqueleto para el objeto remoto. Los pasos 3

y 4 se deben repetir cada vez que se cambie la implementación de la interfaz.

5. Crear el programa del servidor de objeto ServidorEjemplo.java. Compilarlo y revisarlo.

6. Si se desea descarga de resguardo, copiar el fichero resguardo en un directorio apropiadodel servidor HTTP.

7. Si se utiliza el registro RMI y no ha sido ya activado, activarlo. Por ejemplo: rmiregistry<número de puerto>. Alternativamente, se puede codificar la activación en el programadel servidor de objeto.

8. Construir un fichero de políticas de seguridad para la aplicación denominado java.policy ycolocarlo en un directorio apropiado.

9. Activar el servidor, especificando (1) el campo codebase si se utiliza descarga de resguardo,y (2) el fichero de políticas de seguridad.

Algoritmo para desarrollar el software de la parte cliente

1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicación.

2. Obtener una copia del fichero class de la interfaz remota del servidor.

3. Crear el programa cliente ClienteEjemplo.java y compilarlo para generar la clase cliente.

4. Si se desea utilizar descarga de resguardo, obtener una copia del fichero class del resguardoy colocarlo en el directorio actual.

5. Construir un fichero de políticas de seguridad para la aplicación denominado java.policy ycolocarlo en un directorio apropiado.

6. Activar el cliente, especificando el fichero de políticas de seguridad.

71

Page 75: Aplicaciones Distribuidas Resumen Apuntrix

10. CORBA - Common Object Request Broker Architecture

Se presentará una arquitectura alternativa para objetos distribuidos. Se la conoce como Com-mon Object Request Broker Architecture (CORBA). CORBA en primer lugar, proporciona uncaso de estudio que ilustra dos arquitecturas similares, pero en contraste, para un conceptodeterminado, los objetos distribuidos. En segundo lugar, proporciona un ejemplo de una arqui-tectura diseñada para alcanzar la máxima interoperabilidad.

CORBA es una arquitectura que permite que objetos distribuidos interoperen sobre entor-nos heterogéneos, donde los objetos pueden estar implementados en diferentes lenguajes deprogramación y/o desplegados sobre diferentes plataformas.

10.1. Arquitectura básica

La Figura 22 muestra la arquitectura básica de CORBA. Guarda una gran semejanza con laarquitectura RMI. Un cliente de objeto realiza una llamada a un método de un objeto distri-buido. El cliente interactúa con un proxy, un stub, mientras que la implementación del objetointeractúa con un proxy de servidor, un skeleton. Una capa adicional de software, conocida co-mo ORB (Object Request Broker) es necesaria. En el lado del cliente, la capa del ORB actúacomo intermediaria entre el stub y la red y el sistema operativo local del cliente. En el lado delservidor, la capa del ORB sirve de intermediaria entre el skeleton y la red y sistema operativo delservidor. Las capas ORB de ambos extremos son capaces de resolver las diferencias existentes enlo referente a lenguajes de programación, así como las relativas a las plataformas, para ayudar ala comunicación entre los dos extremos. El cliente utiliza un servicio de nombrado para localizarel objeto.

Figura 22: Arquitectura CORBA básica.

10.2. La interfaz de objetos de CORBA

Debido a que CORBA es independiente de lenguaje, la interfaz se define por medio de unlenguaje universal con una sintaxis específica, conocido como CORBA Interface Definition Lan-guage (IDL). La sintaxis de CORBA IDL es muy similar a la de Java, pero un objeto definido enCORBA IDL puede implementarse en un gran número de lenguajes. Para cada uno de estos len-guajes, OMG tiene una traducción estándar de CORBA IDL a dicho lenguaje de programación,de forma que se pueda usar un compilador para procesar las interfaces CORBA y generar losproxies necesarios.

La Figura 23 muestra una aplicación donde el cliente es un programa escrito en Java mientrasque el objeto está implementado en C++.

Figura 23: Independencia de mensajes en CORBA.

72

Page 76: Aplicaciones Distribuidas Resumen Apuntrix

10.3. Protocolos inter-ORB

Para que dos ORB puedan interoperar, OMG ha especificado un protocolo conocido comoGIOP. Un caso especial de este protocolo es el Internet Inter-ORB Protocol (IIOP), que secorresponde con el GIOP aplicado sobre el nivel de transporte de TCP/IP.

La especificación de IIOP incluye los siguientes elementos:

1. Requisitos de gestión de transporte. Especifican qué se necesita para conectarse y desco-nectarse, y los papeles que el cliente y el objeto servidor interpretan.

2. Definición de la representación común de datos. Se necesita definir un esquema de codi-ficación para empaquetar y desempaquetar los datos para cada tipo de datos del IDL.

3. Formatos de los mensajes. Se necesita definir los diferentes formatos de los distintos tiposde mensajes. Cada cliente usa un mensaje de petición para invocar a un método declaradoen la interfaz CORBA de un objeto y recibe un mensaje de respuesta del servidor.

Un ORB que soporte la especificación de IIOP puede interoperar con otro ORB compatible IIOPa través de Internet. De aquí surje la denominación bus de objetos: Internet se ve como un busde objetos CORBA interconectados.

10.4. Servidores de objetos y clientes de objetos

Un servidor de objetos exporta cada objeto distribuido CORBA. Un cliente de objetos ob-tiene la referencia a un objeto distribuido por medio de un servicio de nombres o de directorioy posteriormente invoca los métodos de dicho objeto distribuido.

10.5. Referencias a objetos CORBA

Un objeto distribuido CORBA se localiza por medio de una referencia a objeto. Una referen-cia a un objeto CORBA es una entidad abstracta traducida a una referencia de objeto específicade cada lenguaje por medio del ORB.

OMG especifica un protocolo para referencias abstractas de objetos, conocido como protocoloInteroperable Object Reference (IOR). Un ORB compatible con el protocolo IOR permitirá queuna referencia a objeto se registre y se obtenga desde un servicio de directorio compatible conIOR.

Una IOR es una cadena de caracteres que contiene codificada la información siguiente:

El tipo de objeto.

El ordenador donde se encuentra el objeto.

El número de puerto del servidor de objeto.

Una clave del objeto, una cadena de bytes que identifica al objeto. La utiliza el servidor deobjetos para localizar el objeto internamente.

La representación consiste en un prefijo con los caracteres IOR: seguido por una secuencia hexa-decimal de caracteres numéricos, donde cada carácter representa 4 bits de datos binarios en laIOR.

10.6. Servicio de nombres y servicio de nombres interoperable en CORBA

En el Capítulo 7 se presentó el registro RMI como un servicio de directorio distribuido paraobjetos RMI. CORBA especifica un servicio de directorio con el mismo propósito. El serviciode nombres sirve como un directorio de objetos CORBA, independiente de la plataforma y dellenguaje de programación.

73

Page 77: Aplicaciones Distribuidas Resumen Apuntrix

Servicio de nombres de CORBA

El Servicio de Nombres permite que clientes basados en ORB obtengan las referencias a losobjetos que desean usar. Permite asociar nombres a referencias de objetos.

Para exportar un objeto distribuido, un servidor de objetos CORBA contacta con el Serviciode Nombres para asociar (bind) un nombre simbólico al objeto. Para obtener una referencia a unobjeto, un cliente de objetos solicita que el Servicio de Nombres busque el objeto asociado condicho nombre. El API para el Servicio de Nombres se encuentra especificada por medio de unainterfaz IDL, que incluye métodos que permiten a servidores asociar nombres a objetos y a losclientes resolverlos.

Se define una jerarquía de nombrado estándar de una manera similar a un directorio deficheros. En este esquema de nombrado, un contexto de nombrado se corresponde con unacarpeta o directorio en un árbol de ficheros, mientras que los nombres de objetos se correspondencon los ficheros. El nombre completo de un objeto se denomina nombre compuesto.

La sintaxis para un nombre de objeto es la siguiente: <contexto de nombrado>.<contexto denombrado>.. . . <contexto de nombrado>.<nombre del objeto>. La Figura 24 muestra un ejemplo deuna jerarquía de nombrado.

Figura 24: Un ejemplo de la jerarquía de nombrado de CORBA.

Servicio de nombres interoperable de CORBA

El Interoperable Naming Service (INS) es un sistema de nombrado basado en el formato URLpara el Servicio de Nombres de CORBA. Permite que las aplicaciones compartan un contextoinicial de nombrado y que proporcionen un URL para acceder a un objeto CORBA. Utilizandoeste sistema, un URL del tipo corbaname::acme.com:2050#tienda/ropa/mujer se podría usar paraacceder al objeto tienda/ropa/mujer del servicio de nombres en el puerto 2050 del servidor connombre acme.com.

10.7. Servicios de objetos CORBA

Dentro de las especificaciones de CORBA se encuentran varias que proporcionan serviciosusados habitualmente por los objetos distribuidos para construir aplicaciones. Algunos de losservicios son:

Servicio de concurrencia – proporciona control de concurrencia.

Servicio de eventos – para la sincronización de eventos.

Servicio de log – para registrar eventos.

Servicio de nombres – servicio de directorio.

Servicio de planificación – para planificación de eventos.

74

Page 78: Aplicaciones Distribuidas Resumen Apuntrix

Servicio de seguridad – para gestión de seguridad.

Servicio de negociación – para localizar servicios por tipo.

Servicio de tiempo – un servicio para eventos relativos al tiempo.

Servicio de notificación – para notificación de eventos.

Servicio de transacciones de objetos – para procesamiento de transacciones.

Cada servicio se define por medio de un IDL estándar que puede ser implementado por losdesarrolladores, y los métodos del objeto de servicio se pueden invocar desde cualquier clienteCORBA.

10.8. Adaptadores de objetos

En la arquitectura de CORBA, la implementación de objetos distribuidos actúa con el skeletonpara conectarse con el stub en el lado del cliente. Cuando evolucionó, se añadió un componentesoftware al skeleton en el lado del servidor: el adaptador de objetos. Un adaptador de objetossimplifica las responsabilidades que tiene un ORB asistiéndole en hacer llegar las peticiones delcliente a la implementación del objeto.

Hay diferentes tipos de adaptadores de objetos CORBA. El Portable Object Adapter (POA)permite que una implementación de objeto funcione en varios ORB, de forma que la implemen-tación del objeto sea portable a través de varias plataformas.

10.9. IDL de Java

Se va a ver el IDL de Java. Java IDL incluye un ORB, un compilador IDL-a-Java, y unsubconjunto de los servicios estándar de CORBA. En el resto de este capítulo, se tratará JavaIDL como un ejemplo de entorno CORBA.

Paquetes claves de Java IDL

Java IDL proporciona una serie de paquetes que contienen interfaces y clases para dar soportea CORBA:

El paquete org.omg.CORBA contiene las interfaces y las clases que proporcionan la traduc-ción de las API de CORBA OMG al lenguaje de programación Java.

El paquete org.omg.CosNaming contiene los interfaces y las clases que dan soporte al Servi-cio de Nombrado para Java IDL.

org.omg.CORBA contiene interfaces y clases para soportar el API de acceso al ORB.

Herramientas de Java IDL

Java IDL dispone de un conjunto de herramientas para desarrollar aplicaciones CORBA:

idlj – el compilador IDL-a-Java.

orbd – proceso servidor que da soporte al Servicio de Nombrado.

servertool – proporciona una interfaz en línea de comandos para que los programadoresde aplicaciones puedan registrar/desregistrar objetos, y arrancar/parar servidores.

tnameserv – versión antigua del Servicio de Nombrado (desaconsejado).

Una aplicación CORBA de ejemplo

El ejemplo muestra un objeto CORBA que proporciona un método que devuelve la cadenade caracteres “Hola mundo”.

75

Page 79: Aplicaciones Distribuidas Resumen Apuntrix

Fichero de la interfaz CORBA El punto de arranque de una aplicación CORBA es el desarrollodel fichero de interfaz CORBA escrito en el IDL de OMG. La sintaxis de este fichero de interfazes la misma independientemente de cuáles sean las herramientas CORBA utilizadas. El Listado53 muestra un ejemplo de un posible fichero IDL que declara la interfaz llamada Hola. El métodoapagar() desactiva el ORB y se recomienda incluirlo en todos los interfaces de servicio CORBA.Se pueden declarar una o varias interfaces dentro de un mismo módulo. El modificador onewaydenota que el método apagar requiere sólo una comunicación del cliente al servidor (y ningunarespuesta del servidor).

El fichero IDL puede colocarse en un directorio dedicado para esta aplicación. El fichero secompila usando el compilador idlj de la siguiente forma:

idlj -fall Hola.idl

Listado 53: Hola.idl

1 module HolaApp {2 interface Hola {3 string decirHola();4 oneway void apagar();5 }6 }

La opción -fall es necesaria para que el compilador genere todos los ficheros necesarios parael resto del ejemplo. Si la compilación tiene éxito se generan los siguientes ficheros:

HolaOperations.java

Hola.java

HolaHelper.java

HolaHolder.java

_HolaStub.java

HolaPOA.java

Estos ficheros no necesitan ninguna modificación por su parte. Se explicará brevemente cadauno de estos ficheros en los siguientes párrafos.

HolaOperations.java, el interfaz de operaciones Este fichero (Listado 54), conocido como in-terfaz de operaciones Java, traduce el fichero de interfaz IDL CORBA. Contiene los métodosdefinidos en el fichero IDL original.

Listado 54: HolaApp/HolaOperations.java

1 package HolaApp;2

3 public interface HolaOperations {4 String decirHola();5 void apagar();6 }

Hola.java, el fichero de forma de interfaz Este fichero (Listado 55), denominado fichero defirma de interfaz, extiende clases de CORBA y la interfaz específica de la aplicación, HolaOpera-tions.

Listado 55: HolaApp/Hola.java

1 package HolaApp;2

3 public interface Hola extends HolaOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {}

76

Page 80: Aplicaciones Distribuidas Resumen Apuntrix

HolaHelper.java, la clase de ayuda La clase HolaHelper (Listado 56), proporciona funcionali-dades auxiliares necesarias para dar soporte a los objetos CORBA en el contexto del lenguajede programación Java. Un método, narrow, permite que una referencia a un objeto CORBA sepueda convertir a su tipo correspondiente en Java. La descripción detallada del fichero está másallá del ámbito de este libro.

Listado 56: HolaApp/HolaHelper.java

1 package HolaApp;2

3 abstract public class HolaHelper {4 private static String _id = "IDLHolaApp/Hola1.0";5

6 public static void insert (org.omg.CORBA.any a, HolaApp.Hola that) {7 org.omg.CORBA.portable.OutputStream out = a.create_output_stream();8 a.type(type());9 write(out, that);

10 a.read_value(out.create_input_stream(), type());11 }12

13 public static HolaApp.Hola extract(org.omg.CORBA.Any a) {14 return read(a.create_input_stream());15 }16

17 private static org.omg.CORBA.TypeCode _typeCode = null;18 synchronized public static org.omg.CORBA.TypeCode type() {19 if(_typeCode == null) {20 _typeCode = org.omg.CORBA.ORB.init().create_interface_tc(HolaApp.HolaHelper.

id(), "Hola");21 }22 return _typeCode;23 }24

25 public static String id() {26 return _id;27 }28

29 public static HolaApp.Hola read(org.omg.CORBA.portable.InputStream istream) {30 return narrow(istream.read_Object(_HolaStub.class));31 }32

33 public static void write(org.omg.CORBA.portable.OutputStream ostream, HolaApp.Holavalue) {

34 ostream.write_Object((org.omg.CORBA.Object)value);35 }36

37 public static HolaApp.Hola narrow(org.omg.CORBA.Object obj) {38 if(obj==null)39 return null;40 else if(obj instanceof HolaApp.Hola)41 return (HolaApp.Hola)obj;42 else if(!obj._is_a(id()))43 throw new org.omg.CORBA.BAD_PARAM();44 else {45 org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.

ObjectImpl)obj)._get_delegate();46 HolaApp._HolaStub stub = new HolaApp._HolaStub();47 stub._set_delegate(delegate);48 return stub;49 }50 }51 }

HolaHolder.java, la clase contenedora La clase HolaHolder (Listado 57), contiene una referenciaal objeto que implementa la interfaz Hola. La clase proyecta los parámetros de tipo out o inoutdel IDL a la sintaxis de Java.

Listado 57: HolaApp/HolaHolder.java

77

Page 81: Aplicaciones Distribuidas Resumen Apuntrix

1 package HolaApp;2

3 public final class HolaHolder implements org.omg.CORBA.portable.Streamable {4 public HolaApp.Hola value = null;5

6 public HolaHolder() {}7

8 public HolaHolder(HolaApp.Hola initialValue) {9 value = initialValue;

10 }11

12 public void _read(org.omg.CORBA.portable.InputStream i) {13 value = HolaApp.HolaHelper.read(i);14 }15

16 public void _write(org.omg.CORBA.portable.OutputStream o) {17 HolaApp.HolaHelper.write(o, value);18 }19

20 public org.omg.CORBA.TypeCode _type() {21 return HolaApp.HolaHelper.type();22 }23 }

_HolaStub.java, el fichero de resguardo (stub) La clase _HolaStub (Listado 58) es el fichero deresguardo o stub, el proxy de cliente, que interactúa con el objeto cliente.

Listado 58: HolaApp/_HolaStub.java

1 package HolaApp;2

3 public class _HolaStub extends org.omg.CORBA.portable.ObjectImpl implements HolaApp.Hola {

4

5 public String decirHola() {6 org.omg.CORBA.portable.OutputStream $in = null;7 try {8 org.omg.CORBA.portable.OutputStream $out = _request("decirHola", true);9 $in = _invoke($out);

10 String $result = $in.read_string();11 return $result;12 } catch (org.omg.CORBA.portable.ApplicationException $ex) {13 $in = $ex.getInputStream();14 String _id = $ex.getId();15 throw new org.omg.CORBA.MARSHAL(_id);16 } catch (org.omg.CORBA.portable.RemarshalException $rm) {17 return decirHola();18 } finally {19 _releaseReply($in);20 }21 }22

23 public void apagar() {24 org.omg.CORBA.portable.InputStream $in = null;25 try {26 org.omg.CORBA.portable.OutputStream $out = _request("apagar", false);27 $in = _invoke($out);28 } catch (org.omg.CORBA.portable.ApplicationException $ex) {29 $in = $ex.getInputStream();30 String _id = $ex.getId();31 throw new org.omg.CORBA.MARSHAL(_id);32 } catch (org.omg.CORBA.portable.RemarshalException $rm) {33 apagar();34 } finally {35 _releadeReply($in);36 }37 }38

39 private static String[] _ids = {"IDLHolaApp/Hola1.0"};40 public String _ids() {41 return (String[])_ids.clone();

78

Page 82: Aplicaciones Distribuidas Resumen Apuntrix

42 }43

44 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException {45 String str = s.readUTF();46 String[] args = null;47 java.util.Properties props = null;48 org.omg.CORBA.Object obj = org.omg.CORBA.ORB.init(args, props).string_to_object

(str);49 org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)

obj)._get_delegate();50 _set_delegate(delegate);51 }52

53 private void writeObj(java.io.ObjectOutputStream s) throws java.io.IOException {54 String[] args = null;55 java.util.Properties props = null;56 String str = org.omg.CORBA.ORB.init(args, props).object_to_string(this);57 s.writeUTF(str);58 }59

60 }

HolaPOA.java, el skeleton del servidor y el adaptador de objetos POA La clase HolaPOA(Listado 59) es la combinación del skeleton (proxy asociado al servidor) con el adaptador deobjetos POA (Portable Object Adapter).

Listado 59: HolaApp/HolaPOA.java

1 package HolaApp;2

3 public abstract class HolaPOA extends org.omg.PortableServer.Servant implementsHolaApp.HolaOperations, org.omg.CORBA.portable.InvokeHandler {

4

5 private static java.util.Hashtable _methods = new java.util.Hashtable();6 static {7 _methods.put("decirHola", new java.lang.Integer(0));8 _methods.put("apagar", new java.lang.Integer(1));9 }

10

11 public org.omg.CORBA.portable.OutputStream _invoke(String $method, org.omg.CORBA.portable.InputStream in, org.omg.CORBA.portable.ResponseHandler $rh) {

12 org.omg.CORBA.portable.OutputStream out = null;13 java.lang.Integer _method = (java.lang.Integer)_methods.get($method);14 if(_method == null)15 throw new org.omg.CORBA.BAD_OPERATION(0, org.omg.CORBA.CompletionStatus.

COMPLETED_MAYBE);16

17 switch(_method.intValue()) {18 case 0 {19 String $result = null;20 $result = this.decirHola();21 out = $rh.createReply();22 out.write_string($result);23 break;24 }25 case 1 {26 this.apagar();27 out = $rh.createReply();28 break;29 }30 default {31 throw new org.omg.CORBA.BAD_OPERATION(0, org.omg.CORBA.CompletionStatus.

COMPLETED_MAYBE);32 }33 }34

35 return out;36 }37

38 private static String[] _ids = {"IDLHolaApp/Hola1.0"};39 public String[] _all_interfaces(org.omg.PortableServer.POA poa, byte[] objectId) {

79

Page 83: Aplicaciones Distribuidas Resumen Apuntrix

40 return(String[])_ids.clone();41 }42

43 public Hola _this() {44 return HolaHelper.narrow(super._this_object());45 }46

47 public Hola _this(org.omg.CORBA.ORB orb) {48 return HolaHelper.narrow(super._this_object(orb));49 }50

51 }

La aplicación A continuación se van a ver los ficheros fuente de la aplicación que sé debedesarrollar el programador.

Clases en el servidor Se necesitan dos clases: el servant y el servidor.El servant (Listado 60) es una subclase de HolaPOA. Contiene la definición de cada método

declarado en la interfaz IDL.

Listado 60: HolaApp/HolaImpl.java

1 import HolaApp.*;2 import org.omg.CosNaming.*;3 import org.omg.CosNaming.NamingContextPackage.*;4 import org.omg.CORBA.*;5 import org.omg.PortableServer.*;6 import org.omg.PortableServer.POA;7 import java.util.Properties;8

9 /**10 * El servant (implementación del objeto) para el ejemplo.11 */12 class HolaImpl extends HolaPOA {13 private ORB orb;14

15 public void setORB(ORB orb_val) {16 orb = orb_val;17 }18

19 public String decirHola() {20 return "\nHola mundo!\n";21 }22

23 public void apagar() {24 org.apagar(false);25 }26 }

El servidor (Listado 61) es el responsable de crear e inicializar el ORB, activar el gestor deladaptador de objetos POA, crear una instancia de la implementación del objeto, y de registrar elobjeto en el ORB.

Listado 61: HolaApp/ServidorHola.java

1 import HolaApp.*;2 import org.omg.CosNaming.*;3 import org.omg.CosNaming.NamingContextPackage.*;4 import org.omg.CORBA.*;5 import org.omg.PortableServer.*;6 import org.omg.PortableServer.POA;7 import java.util.Properties;8

9 /**10 * Un servidor para el objeto Hola11 */12 public class ServidorHola {13 public static void main (String[] args) {14 try {

80

Page 84: Aplicaciones Distribuidas Resumen Apuntrix

15 ORB orb = ORB.init(args, null);16 POA rootpoa = (POA)orb.resolve_initial_references("RootPOA");17 rootpoa.the_POAManager().activate(); //activar POAManager18 HolaImpl holaImpl = new HolaImpl();19 holaImpl.setORB(orb); //registrar servant en el ORB20

21 // obtener referencia de objeto del servant22 org.omg.CORBA.Object ref = rootpoa.servant_to_reference(holaImpl);23 // convertirla en una referencia CORBA24 Hola href = HolaHelper.narrow(ref);25

26 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");27 NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);28

29 String name = "Hola";30 NameComponent path[] = ncRef.to_name(name);31 ncRef.rebind(path, href);32

33 System.out.println("ServidorHola preparado...");34 orb.run();35 } catch (Exception e) {36 System.err.println("ERROR " + e);37 e.printStackTrace();38 }39

40 System.out.println("ServidorHola saliendo...");41 }42 }

La aplicación cliente del objeto El Listado 62 muestra un ejemplo de cliente para el objetoHola. El código cliente se debe encargar de crear e inicializar el ORB, buscar el objeto usando elServicio de Nombrado Interoperable, invocar el método narrow del objeto Helper para convertirla referencia del objeto a una referencia de una implementación del objeto Hola, e invocar losmétodos remotos usando dicha referencia.

Listado 62: HolaApp/ClienteHola.java

1 import HolaApp.*;2 import org.omg.CosNaming.*;3 import org.omg.CosNaming.NamingContextPackage.*;4 import org.omg.CORBA.*;5

6 /**7 * Ejemplo de aplicación cliente del objeto.8 */9 public class ClienteHola {

10 static Hola holaImpl;11

12 public static void main (String[] args) {13 try {14 ORB orb = ORB.init(args, null);15 org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");16 NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);17

18 String nombre = "Hola";19 holaImpl = HolaHelper.narrow(ncRef.resolve_str(nombre));20 System.out.println("Obtenido un manejador para el objeto servidor " +

holaImpl);21 System.out.println(holaImpl.decirHola());22 holaImpl.apagar();23 } catch (Exception e) {24 System.err.println("ERROR " + e);25 e.printStackTrace(System.out);26 }27 }28 }

81

Page 85: Aplicaciones Distribuidas Resumen Apuntrix

Compilación y ejecución de una aplicación Java IDL

Procedimiento para compilar y ejecutar aplicaciones Java IDL.

Parte servidora

1. Colóquese en el directorio que contiene el fichero IDL Hola.idl.

2. Ejecute el compilador IDL-a-Java con idlj -fall Hola.idl. Debe utilizarse la opción-fall para generar todo el código de soporte cliente y servidor, el cual se guardará en elsubdirectorio HolaApp.

3. Compile los ficheros .java del directorio HolaApp, incluyendo los stubs y los skeletons, me-diante el comando javac *.java HolaApp/*.java.

4. Arranque el Ddemonio de ORB Java, orbd, que incluye el servidor del Servicio de Nombra-do.

En Unix/Linux: orbd -ORBInitialPort <puerto>&.

En Win: start orbd -ORBInitialPort <puerto>&.

5. Arranque el servidor Hola.

En Unix/Linux: java ServidorHola -ORBInitialPort <puerto> -ORBInitialHostlocalhost.

En Win: start java ServidorHola -ORBInitialPort <puerto> -ORBInitialHostlocalhost.

Parte cliente

1. Obtenga y compile el fichero Hola.idl de la máquina servidora: idlf -fall Hola.idl.Copie el directorio y el subdirectorio creados con sus contenidos a la máquina cliente.

2. En el directorio HolaApp de la máquina cliente, cree el fichero ClienteHola.java. Compile losficheros .java, incluyendo los stubs y los skeletons: javac *.java HolaApp/*.java.

3. Ejecute la aplicación cliente Hola de la siguiente forma: java ClienteHola -ORBInitialHost<ordenador del servidor de nombrado> -ORBInitialPort <puerto>.

Callback de cliente RMI proporciona la posibilidad de realizar callbacks hacia el cliente. Lamisma posibilidad existe en el caso de Java IDL.

82

Page 86: Aplicaciones Distribuidas Resumen Apuntrix

11. Servicios web/Aplicaciones de Internet

Un servicio web es una pieza software que dispone de una funcionalidad específica y quepermite ser empleada en multitud de entornos con independencia del lenguaje de desarrollo. Eléxito del modelo web puede atribuirse a que es un modelo más débilmente acoplado que losmodelos de programación distribuida tradicionales como RPC, RMI o CORBA. Los clientes yservidores web intercambian mensajes que transportan datos de tipo MIME. El destino de unmensaje se especifica indirectamente utilizando una URL.

La idea básica de los servicios web es adaptar el modelo de programación web débilmenteacoplado a su uso en aplicaciones que no estén basadas en el navegador. El objetivo es propor-cionar una plataforma para construir aplicaciones distribuidas utilizando software que se ejecuteentre distintos sistemas operativos, escrito en diferentes lenguajes de programación.

11.1. ¿Qué es un servicio web?

Un servicio web representa un recurso de información o un proceso de negocio, al cual otraaplicación puede acceder a través de la web, y con el cual se puede comunicar a través deprotocolos estándar de Internet.

Los servicios web están diseñados para soportar la comunicación de una aplicación con otraaplicación. Otros tipos de aplicaciones web soportan comunicación entre personas o comunica-ción persona-aplicación. Los servicios web están diseñados para permitir que las aplicaciones secomuniquen sin intervención humana.

Arquitectura de los servicios web (WSA)

Los principios de diseño de las aplicaciones distribuidas basadas en servicios web tienensu erigen en la Arquitectura Orientada a Servicios (SOA). Ejemplos de esta arquitectura seencuentran en tecnologías como RPC, RMI o CORBA. En la Figura 25 se muestra este modeloarquitectónico. Sus tres componentes fundamentales son:

1. Proveedor del servicio, encargado de hacer que el servicio esté disponible. Debe publicarun contrato que describa la interfaz del servicio que ofrece y registrarlo en el agente deservicio.

2. Cliente del servicio, que busca el servicio que necesita a través del agente de servicio.

3. Agente del servicio, que ofrece a los clientes un mecanismo de búsqueda de los serviciospreviamente registrados. El agente le da al cliente las direcciones donde puede encontrarel servicio que necesita y el contrato del mismo.

Figura 25: Arquitectura SOA.

Además, un sistema que implemente este modelo debe soportar tres funcionalidades básicas:

83

Page 87: Aplicaciones Distribuidas Resumen Apuntrix

1. Transporte, es decir cómo se representan los formatos y protocolos usados para comuni-carse con un servicio.

2. Descripción, encargada de definir y usar un lenguaje de descripción adecuado para elservicio. A partir de éste lenguaje es posible generar de forma dinámica y estática el códigode comunicación, así como los delegados y esqueletos necesarios.

3. Descubrimiento, que se encarga de representar el mecanismo usado para registrar o en-contrar un servicio y su contrato o descripción.

A partir de SOA nace la Arquitectura de Servicios Web (WSA), mostrada en la Figura 26 yque converge el modelo SOA y el uso de web como modelo de comunicación. Su característicaprincipal es que es independiente de la plataforma y del lenguaje.

Figura 26: Modelo arquitectónico WSA.

El protocolo básico de los servicios web es XML, que se usa como formato de los mensajes dedatos y como base de otros protocolos de WSA, tales como SOAP, WSDL y UDDI. La utilizaciónde XML garantiza la independencia del lenguaje y de la plataforma. XML por sí solo no puedeimplementar los protocolos de comunicación puesto que las aplicaciones necesitan formatosestándares y protocolos que permitan interpretar de forma apropiada los datos XML. Se handesarrollado tres estándares de facto:

Protocolo Simple de Acceso a Objeto (SOAP). Define un protocolo estándar de comunica-ción para los servicios web.

Lenguaje de Descripción de Servicios web (WSDL). Define un mecanismo estándar paradescribir un servicio web.

Servicio de descripción Universal, Descubrimiento e Integración (WSDL). Proporciona unmecanismo estándar para registrar y encontrar servicios web.

En la Figura 27 se muestra la relación entre las tecnologías descritas aplicadas al modelo SOA.

11.2. Funcionalidad de transporte de WSA: SOAP.

SOAP es un protocolo de mensajería basado en XML extensible que forma la base de losservicios web. SOAP permite a una aplicación enviar un mensaje XML a otra aplicación. Básica-mente SOAP está compuesto de cuatro partes:

Envoltorio SOAP (envelope). Proporciona un mecanismo de identificación de los contenidosdel mensaje y decide cómo se debe procesar el mensaje. Se compone a su vez de dos partes:la cabecera SOAP y el cuerpo SOAP. La cabecera permite añadir información de control odirectivas de mensaje, y se puede usar para implementar lógica asociada a:

84

Page 88: Aplicaciones Distribuidas Resumen Apuntrix

Figura 27: Relación entre SOAP, WSDL y UDDI.

• Transacciones.

• Seguridad.

• Fiabilidad.

• Redireccionamiento.

• Mecanismos de facturación.

Cuerpo SOAP (body). Transporta la carga útil que será enviada con el mensaje SOAP. Puedecorresponder a un documento XML o a una invocación remota.

Marco de trabajo de enlace de transporte SOAP. Define el mecanismo de transporte que sepuede usar al enlazar un cliente con un servicio web. El enlace por defecto es el protocoloHTTP, pero se pueden usar SMTP, JMS, etc.

Marco de trabajo de Serialización SOAP. Es necesario definir cómo se realiza la codifi-cación de los mensajes XML. Este marco define si los datos se pasan como un documentoXML normal, si se le aplica alguna codificación, o si se usan las reglas originales definidaspara SOAP.

Tipos de mensajes SOAP

Existen dos tipos de mensajes SOAP:

Mensajes de tipo RPC. Usando RPC, el desarrollador formula una petición SOAP comoun método con cero o más parámetros. Cuando se construye el cuerpo del mensaje SOAP,se representa el método en una estructura simple donde el elemento (etiqueta) más exte-rior está representado por el nombre del mismo, y los elementos internos representan losparámetros de la operación. La respuesta SOAP es similar, donde sus elementos internosrepresentan los resultados devueltos.

Mensajes de tipo Documento. Permite enviar documentos XML. El emisor es el que envíael mensaje y el receptor determina qué hacer con él. El emisor sólo necesita saber cuál esel formato del mensaje y el punto de acceso (normalmente un URI).

También existe una especificación de mensaje que permite incluir archivos no XML a los mensa-jes. Se pueden así añadir archivos multimedia no codificados con XML.

11.3. Funcionalidad de descripción de WSA: WSDL

WSDL describe un servicio web: qué funcionalidad ofrece, cómo se comunica y dónde esaccesible. Proporciona un mecanismo estructurado que describe:

85

Page 89: Aplicaciones Distribuidas Resumen Apuntrix

Las operaciones que un servicio web puede realizar.

Los formatos de los mensajes que puede procesar.

Los protocolos que soporta.

El punto de acceso al servicio.

Una descripción WSDL define una colección de puntos de acceso a red o puertos. Cada puerto sedefine de forma abstracta con su tipo, que soporta un conjunto de operaciones. Cada operaciónprocesa un conjunto particular de mensajes. Un enlace (binding) relaciona un tipo de puerto conun protocolo y un formato de datos.

Un documento WSDL contiene los elementos que describen el servicio:

1. Tipos (etiqueta <types>). Definen los tipos de datos usados dentro de los mensajes. So-porta datos simples y estructuras complejas, que pueden ser relacionados directamentecon sus tipos correspondientes en los lenguajes de programación. Las herramientas SOAPusan la información de tipo para codificar y decodificar los datos de los mensajes SOAP.

2. Mensajes (etiqueta <message>). Define el formato de un mensaje particular. Se usan comoestructuras de entrada o salida para las operaciones soportadas. Pueden estar compuestospor una o varias partes, cada una de las cuales está asociada a un tipo.

3. Tipo de puerto (etiqueta <portType>. Representa un conjunto de operaciones. Cada ele-mento u operación (etiqueta <operation>) define los mensajes de entrada y salida aso-ciados a la operación.

4. Enlace (etiqueta <binding>). Un elemento enlace relaciona las operaciones y mensajesdefinidos por un tipo de puerto a un protocolo concreto y una especificación de formatode datos. Por ejemplo, puede asociar un tipo de puerto a un interfaz específica que usa elprotocolo HTTP para el transporte y el sistema de codificación de datos SOAP.

5. Servicio (etiqueta <service>). Define una colección de puertos (etiqueta <port>) rela-cionados. Un puerto a su vez relaciona un enlace con la localización (URL) de una instanciadel servicio web.

Usando estos elementos WSDL se puede dividir en tres partes (Figura 28):

1. Interfaz abstracta. Se denomina parte qué del documento WSDL y describe la interfazabstracta del servicio web. Describe un tipo de servicio: conjunto de operaciones que im-plementa el servicio.

2. Enlace concreto. Se denomina parte cómo y describe la asociación de la interfaz abstractacon un conjunto concreto de protocolos. Incluye o importa la parte qué del documentoWSDL asociado.

3. Implementación. Se denomina parte dónde y describe la implementación del servicio. Unproveedor de servicio siempre debe publicar la parte dónde del documento WSDL con elservicio web.

Figura 28: Partes de un documento WSDL.

86

Page 90: Aplicaciones Distribuidas Resumen Apuntrix

En la Figura 29 se puede ver la descripción de un servicio web de ejemplo disponible en ladirección web de la empresa XMethods Inc. Se presenta el servicio web que define el cambio demoneda para diferentes países.

Figura 29: Descripción WSDL del servicio de cambio de moneda.

Como se puede apreciar en la Figura 29, hay dos tipos de mensajes SOAP RPC: uno de peti-ción (<message name="getRateRequest">) y uno de recepción (<message name="getRateResponse">)que usan el estilo de documento RPC con las reglas de codificación dadas por el esquema detipos del W3C (etiquetas xsd:string y xsd:float).

Para cada mensaje definido en la descripción WSDL se generan dos mensajes SOAP RPC,una para el de petición (Listado 63) y otro para la respuesta (Listado 64). En el caso del mensajede petición el cuerpo tiene un elemento más externo con el nombre del método (getRate) y doselementos más externos (country1 y country2) con los parámetros del método y sus valores (Euroy USA).

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body><ns1:getRate xmlns:ns1="urn:xmethods-CurrencyExchange" SOAP-ENV:encodingStyle="

http://schemas.xmlsoap.org/soap/encoding/"><country1 xsi:type="xsd:string">euro</country1><country2 xsi:type="xsd:string">usa</country2>

87

Page 91: Aplicaciones Distribuidas Resumen Apuntrix

</ns1:getRate></SOAP-ENV:Body>

Listado 63: Mensaje SOAP RPC de petición del valor de cambio de moneda.

En el mensaje de respuesta (getRateResponse) sólo es necesario devolver un valor del datopedido.

<SOAP-ENV:Envelopexmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body><ns1:getRateResponse xmlns:ns1="urn:xmethods-CurrencyExchange" SOAP-

ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><return xsi:type="xsd:float">1.14</return>

</ns1:getRateResponse></SOAP-ENV:Body>

Listado 64: Mensaje SOAP RPC de respuesta del servicio web de cambio de moneda.

Los elementos tipo, mensaje y tipo de puerto definen un servicio de forma abstracta. El ele-mento enlace permite relacionar el servicio con un protocolo específico, mientras que el elementoservicio relaciona el tipo de servicio y el enlace a una instancia específica del servicio. Los ele-mentos enlace y servicio pueden ser mantenidos en documentos WSDL distintos con el fin deobtener más flexibilidad.

11.4. Funcionalidad de descubrimiento de WSA: UDDI

UDDI proporciona un mecanismo para registrar y categorizar los distintos servicios web quese pueden ofertar a los clientes y que éstos deben poder localizar a través de dicho mecanismo.Como además UDDI es un servicio web a su vez, se pueden usar mensajes SOAP para usarlo.

El registro UDDI contiene la información sobre los negocios y los servicios que ofrecen. Sepuede organizar de la siguiente manera:

Entidad de negocio. Información sobre el negocio (nombre, descripción, contacto). Cadanegocio tiene asociado un identificador único y una lista de categorías que lo describen.

Servicio de negocio. Lista de servicios ofertados por la entidad. Cada uno de ellos contieneuna descripción del servicio, una lista con las categorías asociadas y una lista de patronesde enlace que contienen información técnica sobre el servicio.

Patrones de enlace. Proporcionan información sobre cómo usar el servicio y dónde encon-trarlo. Además asocian el servicio de negocio con un tipo de servicio.

Tipo de servicio. Define un servicio de forma abstracta a través de una estructura llamadatModel. Varias entidades de negocio pueden ofrecer el mismo tipo de servicio. Por ejemplo,un tModel puede apuntar al documento WSDL que describe el tipo de servicio de formaabstracta.

Cuando se necesita utilizar un servicio web, un desarrollador hace una búsqueda en el registroUDDI, especificando el tipo de servicio que se desea. De la entrada para el tipo de servicio deltModel, se puede obtener una descripción WSDL para la interfaz del servicio. De la entrada/s delpatrón de enlace se puede obtener el enlace al servicio y el punto de acceso. Para acabar, usandola descripción WSDL es posible construir una interfaz de cliente SOAP que se puede comunicarcon el servicio web. En la Figura 30 se puede apreciar que existen dos entradas de patrones deenlace a dos entidades de negocio (A y B) que implementan el mismo tipo de servicio (tModel).De esta manera es posible realizar el enlace con la aplicación cliente de dos maneras:

1. De forma estática. Se puede usar la parte cómo del documento WSDL y generar una interfazde cliente SOAP o un proxy que implemente el enlace requerido para comunicarse con unaimplementación de servicio específica.

88

Page 92: Aplicaciones Distribuidas Resumen Apuntrix

2. De forma dinámica. Se puede usar el enlace dinámico. De esta forma usando la partequé del documento WSDL se puede generar la interfaz abstracta del cliente SOAP quepuede trabajar con cualquier implementación de un tipo de servicio específico. En tiempode ejecución la aplicación cliente puede compilar la parte dónde del documento WSDL ygenerar un proxy dinámico que implemente el enlace.

Figura 30: Descripción de un tipo de servicio con sus patrones de enlace.

Se puede ver el registro UDDI como un servidor de nombres. La diferencia está en la flexibi-lidad y la alta escalabilidad que puede ofrecer UDDI. Además, UDDI permite localizar serviciosno sólo por el nombre, sino también por otras características como pueden ser versiones, infor-mación geográfica, etc.

11.5. Implementación de la arquitectura WSA

Se pueden utilizar los servicios web para construir una aplicación haciendo búsquedas so-bre USSI, interpretando documentos WSDL y construyendo peticiones SOAP (Figura 31). Todoello utilizando analizadores XML estándares. Pero para facilitar el proceso, se han implemen-tado productos que ofrecen estas tecnologías de forma rápida y eficiente. Llamaremos a estosproductos plataformas de servicios web.

Generalmente una plataforma de servicios web está compuesta de herramientas de desarro-llo, un servidor de ejecución y un conjunto de servicios de gestión de la plataforma:

La herramientas de desarrollo se usan para crear los servicios web, generar las descripcio-nes WSDL asociadas, y generar los proxies que permiten a los clientes usar los servicios.

El servidor de ejecución de servicios procesa los mensajes SOAP y proporciona un conte-nedor para los servicios web. Para cada petición, el procesador SOAP analiza el mensaje,traduce los datos XML del mensaje al lenguaje nativo e invoca el servicio. Cuando el ser-vicio termina su trabajo, el servidor traduce los resultados al formato XML, lo empaquetay lo envía en un mensaje de respuesta SOAP, que es enviado a la aplicación cliente.

Las herramientas de gestión proporcionan un mecanismo para desplegar, arrancar, parar,configurar y administrar el servicio web, entre otras posibles utilidades.

La plataforma de servicios web además puede proporcionar o extender nuevas capacidades através de las cabeceras SOAP, por ejemplo soporte de transacciones o fiabilidad en el reparto

89

Page 93: Aplicaciones Distribuidas Resumen Apuntrix

Figura 31: Arquitectura de una plataforma de servicios web.

de mensajes SOAP. En la Figura 32 se muestra un diagrama con las posibles capacidades quepodría soportar la plataforma de servicios web.

11.6. Servicios web [11.3. de Computación Distribuida, M. L. Liu]

Los servicios web proporcionan servicios de red transportados por HTTP, y están siendo pro-puestos como una nueva forma de construir aplicaciones de red desde componentes distribuidosindependientes del lenguaje y de la plataforma. Veremos uno de los protocolos (SOAP – SimpleObject Access Protocol) y una API (API SOAP de Apache) como ejemplos de esta tecnología.

Un servicio web se proporciona por un objeto servidor y se accede por un cliente. El servidory el cliente intercambian mensajes de acuerdo a protocolos estándares desarrollados para losservicios web. La Figura 33 representa la jerarquía del protocolo. Lógicamente, el servidor y elcliente intercambian mensajes en la capa de aplicación. Físicamente, se requiere de una serie deprotocolos para dar soporte al intercambio de mensajes.

Figura 33: Jerarquía de protocolos de servicios web.

La Figura 34 muestra los protocolos predominantes utilizados para servicios web. Aunquetodos son de interés, el resto de este capítulo se centrará en el protocolo SOAP y sus aplicaciones.

La Figura 35 muestra la arquitectura software de un servicio web. El escuchador del servicioen la máquina servidora recoge las peticiones de servicios transmitidas sobre la red. Cuando

90

Page 94: Aplicaciones Distribuidas Resumen Apuntrix

Figura 32: Capacidades proporcionadas por la plataforma de servicios web.

Figura 34: Protocolos de servicios web.

recibe una petición, se reenvía al proxy del servicio. El proxy invoca a la lógica de aplicación delobjeto servicio y transmite el valor devuelto al llamante.

Figura 35: Arquitectura software de servicios web.

11.7. SOAP [11.4. de Computación Distribuida, M. L. Liu]

SOAP es un protocolo que incorpora el paradigma de los objetos distribuidos y los protocolosde Internet. Extiende HTTP para permitir acceso a objetos distribuidos que representan serviciosweb.

Un cliente web manda una petición HTTP, cuyo cuerpo contiene un mensaje con formatoSOAP que representa la llamada a un método de un objeto de servicio. La petición se transmitea un servidor web, que la reenvía, junto con los parámetros de la llamada, al método. A conti-

91

Page 95: Aplicaciones Distribuidas Resumen Apuntrix

nuación se invoca el método. Una vez completado, el valor devuelto por el método se envía alservidor web y a continuación se transmite al cliente web en el cuerpo de la respuesta HTTP.

El mensaje SOAP se codifica en XML. Cada mensaje SOAP tiene un formato sencillo, comose representa en la Figura 36.

Figura 36: Esquema de un mensaje de petición SOAP.

Una petición SOAP

La Figura 37 muestra la sintaxis de una petición HTTP con una petición SOAP. Describiremossus HTTP elementos en los siguientes párrafos.

Figura 37: Una petición HTTP con una petición SOAP.

Líneas de cabecera de la petición HTTP El URI de la primera línea debe especificar el objetoal que se dirige la llamada a método remoto. En el ejemplo es /ejemplos.

El Content Type debe especificarse como text/xml. El charset es una especificación de la repre-sentación de caracteres aceptada.

El Content Length, si está presente, debe ser la longitud en bytes del cuerpo de la petición.

92

Page 96: Aplicaciones Distribuidas Resumen Apuntrix

La línea de cabecera SOAPAction especifica el objeto remoto al que se dirige la petición. Lainterpretación de este elemento depende del programa. En la mayor parte de los casos, el URI yel SOAPAction tendrán el mismo valor.

El cuerpo de la petición Hay dos partes en el cuerpo:

El recubrimiento SOAP se define con el elemento <SOAP-ENV:Envelope>. Tiene un con-junto de atributos requeridos que especifican el esquema de codificación y el estilo delrecubrimiento.

El cuerpo de SOAP está definido con la etiqueta <SOAP-ENV:Body>, y contiene un soloelemento, que representa la llamada al método. Junto con el elemento se especifican elnombre del método (obtenerNombreEstado), el nombre de cada parámetro (numestados), elvalor de cada parámetro (41) y el tipo de datos de cada parámetro (int).

Tipos de datos SOAP tiene un rico conjunto de tipos de datos independientes del lenguaje, queestán basados en los tipos de datos de los esquemas XML. La Tabla 11.1 resume un subconjuntode los principales tipos de datos escalares soportados por un subconjunto de SOAP 1.1.

Tabla 11.1: Tipos de datos escalares del esquema XML.

Valor del atributo Tipo Ejemplo

xsd:int Entero con signo de 32-bit -12

xsd:boolean Valor booleano: 1 ó 0 1

xsd:string Cadena de caracteres Hola Mundo

xsd:float o xsd:double Número de coma flotante con signo -12,214

xsd:timeInstant Fecha/Hora 2001-03-27T00:00:01-08:00

SOAP-ENC:base64 Binario codificado en Base64 gdGhpcyE=

Los tipos de datos no escalares también están soportados en SOAP. Algunos de estos tiposson:

Estructuras. Un valor puede ser una estructura, que se especifica con un elemento XML quecontiene subelementos. Las estructuras pueden estar anidadas y pueden contener cualquierotro tipo de datos, incluyendo una matriz. Un ejemplo de una estructura de dos elementoses:

<param><limiteInferior xsi:type=”xsd:int”>19</limiteInferior><limiteSuperior xsi:type=”xsd:int”>139</limiteSuperior>

</param>

Matrices. Un valor puede ser una matriz, que se especifica como un elemento XML con unatributo SOAP-ENC:arrayType cuyos valores comienzan con ur-type[<número de elementos dela matriz>]. El siguiente es un ejemplo de una matriz de cuatro elementos:

<param SOAP-ENC:arrayType=”xsd:ur-type[4]” xsi:type=”SOAP-ENC:Array”><item xsi:type=”xsd:int”>12</item><item xsi:type=”xsd:string”>Egipto</item><item xsi:type=”xsd:boolean”>0</item><item xsi:type=”xsd:int”>-31</item>

</param>

Objetos. Se puede transmitir un objeto en la petición/respuesta SOAP si el proveedor del ser-vicio define y registra el tipo del objeto como un subtipo, y las dos partes proporcionan unserializador y deserializador apropiado. A continuación el nombre del subtipo se declaracomo el atributo xsi:type del parámetro.

93

Page 97: Aplicaciones Distribuidas Resumen Apuntrix

Una respuesta SOAP

El Listado 65 muestra una respuesta HTTP que contiene una respuesta SOAP existosa. Ob-sérvese que el content type es text/xml.

HTTP/1.1 200 OKConnection: closeContent Length: 499Content-Type: text/xml; charset=utf-8Date: Wed, 28 Mar 2001 05:05:04 GMTServer: UserLand Frontier/7.0-WinNT

<?xml version="1.0"?><SOAP-ENV:Envelope SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"xmlns:SOAPENC="http;//schemas.xmlsoap.org/soap/encoding/"xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body><m:obtenerNombreEstadoResponse xmlns:m="http;//soapware.org/">

<Resut xsi:type="xsd:string">Dakota del Sur</Result></m:obtenerNombreEstadoResponse>

</SOAP-ENV:Body></SOAP-ENV:Envelope>

Listado 65: Una respuesta HTTP que contiene una respuesta SOAP con éxito.

El único elemento contenido en <SOAP-ENV:Body> tiene un nombre que coincide con elnombre del método que ha sido llamado, con la palabra Response añadida al final del nombredel método (obtenerNombreEstadoResponse). El tipo de datos (string) y el valor (Dakota del Sur)del valor devuelto está contenido en el subelemento Result.

Una llamada a método SOAP puede fallar. Cuando esto sucede, la respuesta HTTP (Listado66) contiene un cuerpo SOAP que define un código y una cadena de error. El código de error(SOAP-ENV:Client) identifica el error, mientras que la cadena de error proporciona la descripcióndel mismo.

HTTP/1.1 500 ErrorConnection: closeContent Length: 511Content-Type: text/xml; charset=utf-8Date: Wed, 28 Mar 2001 05:06:32 GMTServer: UserLand Frontier/7.0-WinNT

<?xml version="1.0"?><SOAP-ENV:Envelope SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"xmlns:SOAPENC="http;//schemas.xmlsoap.org/soap/encoding/"xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body><SOAP-ENV:Fault>

<faultcode>SOAP-ENV:Client</faultcode><faultstring>No se puede llamar a obtenerNombreEstado porque hay demasiados

parámetros.</faultstring></SOAP-ENV:Fault>

</SOAP-ENV:Body></SOAP-ENV:Envelope>

Listado 66: Una respuesta HTTP que contiene una llamada a método SOAP fallida.

Apache SOAP

Escribir código para generar directamente la sintaxis XML para las peticiones y respuestasSOAP puede ser tedioso y propenso a errores. Han aparcido numerosas API para SOAP parafacilitar la programación que compete a las peticiones/respuestas SOAP, como Apache SOAP oApache AXIS (para Java).

94

Page 98: Aplicaciones Distribuidas Resumen Apuntrix

La clase RPCMessage La clase RPCMessage de Apache SOAP encapsula una petición SOAP. Unobjeto de esta clase contiene las siguientes instancias de campos: targetURI, methodName, paramsy header, que representan los diferentes campos de una petición SOAP.

La clase Call Es una subclase de la clase RPCMessage y representa una llamada a métodoremoto. Se puede crear un objeto de esta clase en un programa cliente SOAP, que puede llamaral método invoke para realizar la llamada a método remoto.

La clase Parameter Un objeto de esta clase representa tanto parámetros como los valores de-vueltos por una llamada a método. En el cliente se crea un objeto de esta clase por cada pa-rámetro de método remoto. En el servidor, se construye un objeto de esta clase para el valordevuelto.

La clase Response Un objeto Response representa la respuesta de una llamada a método. Tantoel cliente como el servidor utilizan objetos Response para representar el resultado de una invoca-ción a método. El servidor crea la respuesta, y el cliente extra información de la respuesta.

La clase Fault Un objeto Fault representa el contenido y la semántica del elemento <SOAP-ENV:Fault>, y lo devuelve al método getFault ejecutado por el cliente. En el código de ejemplo,el método getFaultString se invoca desde un cliente para recibir la descripción del error que causóel fallo de la llamada a método.

Servicios web ya implementados

La idea de los servicios web es permitir a los desarrolladores de software hacer uso deservicios ya implementados. Hay disponibles cierto número de servicios web para aquellos queestén interesados en experimentar con la tecnología [http://xmethods.net].

Invocación de un servicio web utilizando Apache SOAP

El Listado 67 muestra el código de ejemplo de un programa que invoca a un servicio SOAP.

Listado 67: Un ejemplo de cliente de servicio web.

1 import java.io.*;2 import java.net.*;3 import java.util.*;4 import org.apache.soap.util.xml.*;5 import org.apache.soap.*;6 import org.apache.soap.rpc.*;7

8 public class TempClient {9

10 public static void main (String[] args) {11 try {12 URl url = new URL(http://services.xmethods.com:80/soap/servlet/rpcrouter);13 String zipcode = "94320";14 float temp = getTemp(url, zipcode);15 System.out.println("La temperatura es " + temp);16 } catch (Exception e) {17 e.printStackTrace();18 }19 }20

21 public static float getTemp(URL url, String zipcode) throws Exception {22 Call call = new Call();23

24 String encodingStyleURI = Constant.NS_URI_SOAP_ENC;25 call.setEncodingSttyleURI(encodingStyleURI);26

27 call.setTargetObjectURI("urn:xmethods-Temperature");28 call.setMethodName("getTemp");29

30 Parameter aParam = new Parameter("zipcode", String.class, zipcode, null);

95

Page 99: Aplicaciones Distribuidas Resumen Apuntrix

31 Vector params = new Vector();32 params.addElement(aParam);33 call.setParams(params);34

35 Response resp = call.invoce(url, "");36

37 if(resp.generatedFault()) {38 Fault f = resp.getFault();39 System.err.println("Fault=" + f.getFaultCode() + ", " + f.getFaultString());40 throw new Exception(f.getFaultString());41 } else {42 Parameter result = resp.getReturnValue();43 Float readOut = (Float)result.getValue();44 return readOut.floatValue();45 }46 }47

48 }

Para prepararse para la invocación de un método proporcionado por el servicio web, seinstancia el objeto Call y se le asignan valores (líneas 22-28).

Para preparar los argumentos para la invocación, se instancia un objeto de la clase Paramaterpara cada parámetro. Cada objeto Parameter se inicializa con el nombre, el tipo de datos, el valory el estilo de codificación del argumento (línea 30).

La lista de parámetros se recoge en un vector (líneas 31-32) y a continuación se asocia elvector al objeto Call (línea 33).

Para realizar la llamada a método del servicio web, se especifica el método invoke() del objetoCall en el URL (línea 35), donde url se refiere a un objeto de la clase Java URL, instanciado conel servicio web URL (línea 12).

Implementación de un servicio web utilizando Apache SOAP

Un servicio web se define utilizando una interfaz Java, que contiene las declaraciones delos métodos proporcionados por el servicio. El listado 68 muestra la interfaz ITemp para unservicio web de ejemplo, Temp, que proporciona el método getTemp llamado por nuestro clientedel Listado 67.

Listado 68: Una interfaz Java para un servicio web sencillo.

1 /**2 * Ejemplo de interfaz de objeto de servicio SOAP.3 */4 public interface ITemp {5

6 float getTemp(String zipCode);7

8 }

La interfaz se implementa como una clase de Java. El Listado 69 muestra una definición deejemplo de la clase Temp, que implementa a ITemp.

Listado 69: Implementación de un servicio web sencillo.

1 public class Temp implements ITemp {2

3 public float getTemp(String zipCode) {4 System.out.println("Temperatura para el código postal " + zipCode + " solitada.

");5 return 74.5F; // por simplicidad del ejemplo, devuelve constante6 }7

8 }

Un servicio SOAP necesita ser instalado y configurado en la máquina servidora, y este pro-cedimiento depende de la implementación.

96