Вы находитесь на странице: 1из 99

Aplicaciones Distribuidas

Curso 2014/15

Resumen de la asignatura
para apuntrix.com

ndice
1. Introduccin a la computacin distribuida
1.1. Definiciones . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. La historia de la computacin distribuida . . . . . . . .
1.3. Diferentes formas de computacin . . . . . . . . . . . .
1.4. Virtudes y limitaciones de la computacin distribuida
1.5. Conceptos bsicos de sistemas operativos . . . . . . . .
1.6. Conceptos bsicos de redes . . . . . . . . . . . . . . . .
1.7. Conceptos bsicos de ingeniera del software . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

1
1
1
1
2
2
5
8

2. IPC - Comunicacin entre procesos


2.1. Un arquetipo de interfaz de programacin para comunicacin entre procesos
2.2. Sincronizacin de eventos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3. Temporizadores e hilos de ejecucin . . . . . . . . . . . . . . . . . . . . . . . .
2.4. Interbloqueos y temporizadores . . . . . . . . . . . . . . . . . . . . . . . . . .
2.5. Representacin de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6. Codificacin de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.7. Protocolos basados en texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.8. Protocolos de solicitud-respuesta . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9. Diagrama de eventos y diagrama de secuencia . . . . . . . . . . . . . . . . . .
2.10. Comunicacin entre procesos orientada y no orientada a conexin . . . . . .
2.11. Evolucin de los paradigmas de comunicacin entre procesos. . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

11
11
11
11
11
12
12
13
13
13
14
14

3. Paradigmas de computacin distribuida


3.1. Paradigmas y abstraccin . . . . . . . . . .
3.2. Una aplicacin de ejemplo . . . . . . . . . .
3.3. Paradigmas para aplicaciones distribuidas
3.4. Comparativa . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

16
16
16
16
21

4. El API de sockets
4.1. Antecedentes . . . . . . . . . . . . . . . . . . .
4.2. La metfora del socket en IPC . . . . . . . . . .
4.3. El API de sockets datagrama . . . . . . . . . . .
4.4. El API de sockets en modo stream . . . . . . . .
4.5. Sockets con operaciones de E/S no bloqueantes
4.6. El API de sockets seguros . . . . . . . . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

23
23
23
23
29
34
34

5. El paradigma cliente-servidor
5.1. Antecedentes . . . . . . . . . . . . . . . . . . . .
5.2. Cuestiones sobre el paradigma cliente-servidor
5.3. Ingeniera de software de un servicio de red . .
5.4. Servidores orientados a conexin y sin conexin
5.5. Servidor iterativo y servidor concurrente . . . .
5.6. Servidores con estado . . . . . . . . . . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

36
36
36
37
43
47
49

7. Objetos distribuidos
7.1. Paso de mensajes frente a objetos distribuidos
7.2. Una arquitectura tpica de objetos distribuidos
7.3. Sistemas de objetos distribuidos . . . . . . . .
7.4. Llamadas a procedimientos remotos . . . . . .
7.5. RMI (Remote Method Invocation) . . . . . . . . .
7.6. La arquitectura de Java RMI . . . . . . . . . . .
7.7. API de Java RMI . . . . . . . . . . . . . . . . .
7.8. Una aplicacin RMI de ejemplo . . . . . . . . .
7.9. Pasos para construir una aplicacin RMI . . .
7.10. Pruebas y depuracin . . . . . . . . . . . . . .
7.11. Comparacin entre RMI y el API de sockets . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

52
52
52
53
53
53
54
55
58
60
61
61

.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

8. RMI avanzado
8.1. Callback de cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.2. Descarga de resguardo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.3. El gestor de seguridad de RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62
62
68
68

10. CORBA - Common Object Request Broker Architecture


10.1. Arquitectura bsica . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2. La interfaz de objetos de CORBA . . . . . . . . . . . . . . . . . . . . .
10.3. Protocolos inter-ORB . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.4. Servidores de objetos y clientes de objetos . . . . . . . . . . . . . . .
10.5. Referencias a objetos CORBA . . . . . . . . . . . . . . . . . . . . . . .
10.6. Servicio de nombres y servicio de nombres interoperable en CORBA
10.7. Servicios de objetos CORBA . . . . . . . . . . . . . . . . . . . . . . . .
10.8. Adaptadores de objetos . . . . . . . . . . . . . . . . . . . . . . . . . .
10.9. IDL de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

72
72
72
73
73
73
73
74
75
75

11. Servicios web/Aplicaciones de Internet


11.1. Qu es un servicio web? . . . . . . . . . . . . . . . . . . . .
11.2. Funcionalidad de transporte de WSA: SOAP. . . . . . . . . .
11.3. Funcionalidad de descripcin de WSA: WSDL . . . . . . . .
11.4. Funcionalidad de descubrimiento de WSA: UDDI . . . . . .
11.5. Implementacin de la arquitectura WSA . . . . . . . . . . .
11.6. Servicios web [11.3. de Computacin Distribuida, M. L. Liu]
11.7. SOAP [11.4. de Computacin Distribuida, M. L. Liu] . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

83
83
84
85
88
89
90
91

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

1.
1.1.

Introduccin a la computacin distribuida


Definiciones

Un monoprocesador o la computacin monoltica utiliza una nica unidad central de proceso o CPU para ejecutar uno o ms programas por cada aplicacin.
Un sistema distribuido es un conjunto de computadores independientes, interconectados a
travs de una red y que son capaces de colaborar con el fin de realizar una tarea. Los computadores se consideran independientes cuando no comparten memoria ni espacio de ejecucin
de los programas. Dichos computadores se denominan computadores ligeramente acoplados,
frente a los computadores fuertemente acoplados, que pueden compartir datos a travs de un
espacio de memoria comn.
La computacin distribuida es computacin que se lleva a cabo en un sistema distribuido.
Un servicio de red es un servicio proporcionado por un tipo de programa especial denominado servidor en una red.
Una aplicacin de red es una aplicacin para usuarios finales, que se ejecuta en computadores conectados a travs de una red.
La diferencia entre servicios y aplicaciones de red no es siempre ntida y estos trminos frecuentemente se intercambian.

1.2.

La historia de la computacin distribuida

La conexin de computadores aislados de forma que los datos se pudieran intercambiar


fue una progresin natural. El primer RFC (Request For Comments) de Internet, RFC 1, es una
propuesta que especifica cmo las mquinas participantes pueden intercambiar informacin con
otras a travs del uso de mensajes. Hasta el da de hoy, el correo electrnico y la transferencia de
ficheros siguen siendo dos de los ms populares servicios de red. Sin embargo, el ms conocido
es indudablemente la World Wide web.

1.3.

Diferentes formas de computacin

Para comprender qu significa la computacin distribuida, resulta instructivo analizar diferentes formas de computacin.
Computacin monoltica
En la forma ms sencilla de computacin, un nico computador se utiliza para la computacin. Dicho computador slo puede utilizar aquellos recursos a los que tiene acceso de manera
inmediata. Esta forma se denomina computacin monoltica. En su forma ms bsica se denomina computacin monoltica monousuario, donde un nico usuario utiliza el computador a la
vez.
La computacin monoltica permite la convivencia de mltiples usuarios, que pueden compartir de forma concurrente los recursos de un nico computador a travs de una tcnica denominada tiempo compartido. El computador que proporciona el recurso centralizado se denomina mainframe. Los usuarios, que podran estar dispersos geogrficamente, se pueden conectar al
mainframe durante una sesin a travs de dispositivos denominados terminales.
Computacin distribuida
La computacin distribuida implica el uso de mltiples computadores conectados a la red,
cada uno de los cuales tiene su propio procesador o procesadores y otros recursos. Un usuario
que utilice una estacin de trabajo puede usar los recursos del computador local. A travs de
la interaccin entre el computador local y los computadores remotos, el usuario tambin puede
acceder a los recursos de estos ltimos. La web es un ejemplo de este tipo de computacin. El
uso de un navegador para visitar un sitio web implica la ejecucin de un programa en un sistema
local que interacta con otro programa que se ejecuta en un sistema remoto.

Computacin paralela
La denominada computacin paralela utiliza ms de un procesador simultneamente para
ejecutar un nico programa. Suele ser difcil dividir un programa de forma que CPU separadas
ejecuten diferentes porciones del programa sin ninguna interaccin.
Hoy en da, la computacin paralela se utiliza principalmente en computacin cientfica a
gran escala.
Computacin cooperativa
El trmino computacin distribuida se ha aplicado tambin a proyectos de computacin cooperativa tales como el de la bsqueda de inteligencia extraterrestre (SETI). Estos proyectos dividen
la computacin a gran escala entre las estaciones de trabajo de las mquinas de Internet, utilizando ciclos de CPU excedentes.

1.4.

Virtudes y limitaciones de la computacin distribuida

Diferentes razones para la popularidad de la computacin distribuida:


Los computadores y el acceso a la red son econmicos. Los computadores personales
actuales tienen una potencia superior a los primeros mainframes, adems de tener mucho
menor tamao y precio. Adems, la conexin a Internet est disponible universalmente y
es econmica.
Comparticin de recursos. La arquitectura de la computacin distribuida refleja la arquitectura de computacin de las organizaciones modernas. Mediante ella, las organizaciones
pueden utilizar sus recursos de forma efectiva.
Escalabilidad. En la computacin monoltica, los recursos disponibles estn limitados por
la capacidad de un computador. La computacin distribuida proporciona escalabilidad,
debido a que permite incrementar el nmero de recursos compartidos segn la demanda.
Tolerancia a fallos. La computacin distribuida permite que un recurso pueda ser replicado con el fin de dotar al sistema tolerancia a fallos. El desarrollador que disea e
implementa un sistema es el responsable de maximizar la tolerancia a fallos del mismo.
La computacin distribuida tambin tiene algunas desventajas:
Mltiples puntos de fallo. Hay ms puntos de fallo en la computacin distribuida. Debido
a que mltiples computadores estn implicados en la computacin distribuida, y todos son
dependientes de la red para su comunicacin.
Aspectos de seguridad. En un sistema distribuido hay ms oportunidades de ataques no
autorizados. La gestin es descentralizada y frecuentemente implica a un gran nmero
de organizaciones independientes. La descentralizacin hace difcil implementar y ejecutar
polticas de seguridad.

1.5.

Conceptos bsicos de sistemas operativos

A continuacin se describen algunos de los conceptos implicados en la ejecucin de programas en computadores actuales.
Programas y procesos de computacin
Un programa software es un artefacto construido por un desarrollador software utilizando
alguna forma de lenguaje de programacin. Cuando un programa se ejecuta en un computador
se representa como un proceso. Un proceso consiste en un programa que se ejecuta, sus valores actuales, la informacin de estado y los recursos utilizados por el sistema operativo para
gestionar su ejecucin.
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 aplicacin Java tiene un mtodo
principal (main) y se ejecuta como un proceso independiente (standalone).
2

Un applet no tiene un mtodo main y se ejecuta mediante el uso de un navegador o de la


herramienta que permite ver applets, appletviewer. un servlet es parecido al applet en el hecho
de que no tiene un mtodo main. Se ejecuta en el contecto de un servidor web.
Un programa Java se compila y se convierte a un cdigo denominado bytecode. Cuando se
ejecuta, la Mquina Virtual Java (JVM) traduce el bytecode a cdigo mquina nativo del computador. Debido a que el bytecode es un cdigo intermedio independiente del tipo de mquina, se
dice 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("Cul es tu nombre?");
nombre = teclado.readLine();
System.out.print("Hola " + nombre);
System.out.println(" - Bienvenido a CSC369.\n");
}
}
Listado 1: Una aplicacin stand-alone Java y el cdigo 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>

<hr>
<a href="HolaMundo.java">El fichero fuente.</a>
Listado 2: Un applet (arriba) y la pgina web (abajo) que permite activarlo.

import
import
import
import

java.io.*;
java.text.*;
java.util.*;
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 cabecera
response.setContentType("text/html");
//a continuacin escribir los datos de la respuesta
salida = 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 pgina web (abajo) qie permite activarlo.

Programacin concurrente
La programacin concurrente consiste en la ejecucin simultnea de procesos, y existen tres
clases:
Procesos concurrentes ejecutados en mltiples computadores. Procesos separados ejecutando concurrentemente en computadores independientes interconectados a travs de una
red. Los procesos interactan con otros procesos mediante el intercambio de datos sobre la
red, pero su ejecucin es por otra parte completamente independiente.
Procesos concurrentes ejecutados en un nico computador. La concurrencia puede ser
real o virtual. La verdadera concurrencia multitarea slo es posible si el computador tiene
mltiples CPU. En un computador con una sola CPU, se utiliza tiempo compartido para permitir que los procesos puedan ejecutarse por turnos, creando la ilusin de que se
ejecutan en paralelo.
Programacin concurrente dentro de un proceso. Muchas veces un nico programa necesita iniciar diferentes tareas que se ejecuten concurrentemente. Por ejemplo, un programa
podr necesitar realizar otras tareas mientras espera indefinidamente por la entrada de un
usuario en una interfaz de ventanas.

Procesos padres e hijos


En tiempo de ejecucin, un proceso puede crear procesos hijos. El proceso original, denominado
proceso padre, contina ejecutndose simultneamente con el proceso hijo. Un proceso hijo es
un proceso completo, y un proceso padre puede saber cundo uno de sus procesos hijos ha
finalizado.
Threads o hilos
En lugar de procesos hijos, un proceso puede crear threads o hilos, tambin conocidos como
procesos ligeros. Los hilos poseen un mnimo de informacin de estado, comportndose por lo
dems de la misma forma que los procesos, pero implican menos sobrecarga.
La ejecucin concurrente de los hilos puede ocasionar una condicin de carrera, que ocurre
cuando una serie de mandatos de un programa se ejecutan de una forma arbitraria e intercalada,
pudiendo llevarse a cabo una ejecucin no determinista.
Las condiciones de carrera se pueden evitar si se utiliza exclusin mutua dentro de un
segmento de cdigo, denominado regin crtica.
Hilos Java
La mquina virtual Java permite que una aplicacin tenga mltiples hilos ejecutando concurrentemente. Se pueden crear otros hilos adicionales a partir de un hilo activo, y cada hilo se
ejecutar independientemente y en paralelo con el resto hasta que termine.
Para permitir el uso de hilos en un programa, Java proporciona una clase denominada thread
y una interfaz denominada runnable. En Java hay dos formas de crear un nuevo hilo de ejecucin:
1. Declarar una clase como subclase de la clase thread. Esta subclase debe sobrescribir el el
mtodo run de la clase thread.
2. Declarar una clase que implemente la interfaz runnable. Esta clase implementa el mtodo
run de dicha interfaz.
La manera ms sencilla de evitar las condiciones de carrera en Java es a travs de la utilizacin de
los mtodos estticos sincronizados. Un mtodo esttico que contenga en su cabecera la palabra
reservada synchronized puede ejecutarse por un nico hilo simultneamente.

1.6.

Conceptos bsicos de redes

Protocolos
Un protocolo es un conjunto de reglas que los participantes deben seguir. Los protocolos
deben estar definidos formalmente e implementados de una manera precisa. Debe existir un
conjunto de reglas que especifiquen las siguientes cuestiones:
Cmo se codifican los datos intercambiados?
Cmo los eventos (envo, recepcin) se sincronizan (ordenan) de modo que los participantes puedan enviar y recibir informacin de una forma coordinada?
Por ejemplo, el protocolo HTTP especifica las reglas que deben seguir un proceso del navegador
web y un proceso del servidor web. Es importante entender que un protocolo es distinto de su
implementacin.
Arquitecturas de red
La arquitectura de red clsica se denomina arquitectura OSI y divide las funciones complejas de una red en siete capas. Todas o parte de estas funciones deben estar presentes en un
computador que participa en la comunicacin de datos.
La arquitectura de red de Internet est representada en la Figura 1, y est formada por
cuatro capas: fsica, Internet, transporte y aplicacin. La capa fsica proporciona las funciones
de transmisin de seales. La capa Internet permite dirigir y entregar un paquete de datos a un
computador remoto. La capa de transporte proporciona las funciones necesarias para la entrega
de paquetes de datos a un proceso especfico. Finalmente, la capa de aplicacin permite que los
mensajes se puedan intercambiar entre los programas.
5

Figura 1: La arquitectura de red de Internet

Una arquitectura de capas hace posible que los programas se escriban como si los datos se
intercambiaran directamente (vase las lneas 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 un
esquema de nombrado particular para identificar los computadores en una red y para encaminar los datos. En la capa de transporte, hay dos protocolos ampliamente utilizados: TCP para
proporcionar una comunicacin orientada a conexin, y UDP que ofrece una comunicacin sin
conexin. En la capa de aplicacin, existen diferentes protocolos especificados para aplicaciones
de red, tales como FTP, SNMP y HTTP. El conocido protocolo TCP/IP es un conjunto de protocolos que incluye a los protocolos de Internet y transporte de esta arquitectura. Una aplicacin
de Internet debe ejecutarse en un computador que implemente esta parte de la arquitectura de
Internet, denominada pila de protocolos TCP/IP.
Comunicacin orientada a conexin frente a comunicacin sin conexin
En una comunicacin orientada a conexin, una conexin, que puede ser fsica o lgica, se
establece entre dos partes, el emisor y el receptor. Una vez establecida la conexin, los datos
pueden enviarse continuamente a travs de la conexin hasta que la sesin finaliza. En este
modo de comunicacin no es necesario especificar explcitamente la direccin del destinatario
para cada paquete de datos individual durante el tiempo que la conexin se utilice.
La comunicacin sin conexin implica que no existe conexin. En su lugar, los datos se envan
mediante el uso de paquetes y cada emisor debe indicar de forma explcita en cada paquete la
direccin del receptor.
En una red de datos es ms sencillo proporcionar una comunicacin sin conexin. Sin embargo, la falta de conexin puede implicar la prdida de paquetes de datos en la entrega o la
entrega fuera de orden de los mismos.
Por otro lado, la comunicacin orientada a conexin puede asegurar la entrega segura y
ordenada a travs de una conexin establecida, pero con el coste adicional de la sobrecarga que
implica este proceso.
Recursos de red
Por recursos de red se entiende aquellos recursos que estn disponibles para los participantes
de una comunidad de computacin distribuida. Por ejemplo, en Internet los recursos de red
incluyen hardware tal como los computadores o equipamiento, y software. Una clase importante
de recursos de red son los servicios de red, tales como la web o el servicio de transferencia de
ficheros, que son implementados por procesos que se ejecutan en computadores.
Uno de los retos claves en la computacin distribuida es la identificacin nica de los recursos
disponibles en la red.
Identificacin de nodos y direcciones del protocolo de Internet
Fsicamente, 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 de
alto ancho de banda que constituyen el esqueleto central o backbone de la red. Conectadas a este

backbone existen redes individuales. Los computadores con soporte TCP/IP, denominados nodos
o mquinas de Internet, estn unidos a redes individuales.
A continuacin se analiza el esquema de identificacin de nodos especificado en la versin 4
de IP, conocida como IPv4. En IPv4, cada mquina de Internet se identifica por una nica cadena
de 32 bits. Cada direccin IP debe identificar tanto la red en la cual la mquina reside como la
mquina en s.
La mayora de los usuarios tienen problemas para memorizar una cadena de 32 bits, por
tanto es preferible utilizar un nombre simblico para identificar un computador. Esta es la razn
por la que la comunidad de Internet adopt el sistema de nombrado de dominio (DNS). Cada
vez que se utiliza el correo electrnico o se visualiza una pgina web, se identifica la mquina
de Internet utilizando un nombre de dominio basado en el protocolo DNS.
Cada nombre de dominio corresponde a una direccin IP, aunque esta asociacin no tiene por
qu ser permanente. La resolucin de un nombre de dominio para obtener la correspondiente
direccin IP y viceversa se lleva a cabo a travs de un servicio conocido como resolucin de
nombres DNS.
Identificacin de procesos a travs de puertos
En las aplicaciones de red, los datos deben entregarse a un proceso especfico que se ejecuta
en un computador. Por tanto, se necesita un esquema de nombrado que permita identificar
de forma nica un proceso. Hay muchos esquemas que permiten realizar esto. Por ejemplo, una
posibilidad es utilizar un nico identificador de proceso (PID), que le asigna el sistema operativo
al proceso. En Internet, el protocolo utilizado para identificar un proceso usa una entidad lgica
conocida como puerto de protocolo o simplemente puerto. Un proceso que desee intercambiar
datos con otro proceso utilizando TCP o UDP debe tener asignado uno de estos puertos. Una
aplicacin que desee enviar datos a un proceso actualmente asociado al puerto p en la mquina
M, debe dirigir los datos a (M, p).
En los protocolos TCP y UDP, los nmeros entre el 0 y el 1023 estn reservados para servicios
conocidos. Estos puertos se denominan puertos bien conocidos (well-known).
Direcciones de correo electrnico
Una direccin de correo electrnico utiliza el formato nombreUsuario@nombreDominio. Cuando se enva un correo electrnico, un programa de correo electrnico en el computador correspondiente al nombre de dominio especificado entrega el correo al buzn del usuario especificado
en este sistema.
URL
Cuando se introduce una cadena, tal como http://www.google.es en el navegador web
para visitar un determinado sitio web, se est utilizando un URL.
Un URL es un esquema de nombrado que se encuentra debajo de un esquema ms general
denominado URI. Los URI son cadenas cortas que identifican recursos en la web, incluyendo
documentos, imgenes, ficheros, etc. El esquema URI permite identificar de una forma uniforme
estos recursos.
URL es un trmino informal asociado con populares esquemas URI para protocolos tales
como HTTP , FTP o correo electrnico.
URN es un esquema especificado por el RFC2141 y otros documentos relacionados, que permite el uso de identificadores de recursos persistentes e independientes de su localizacin. Un
URN proporciona nombres persistentes e independientes de su localizacin. Un URN proporciona nombres persistentes dentro de un espacio de nombres, permitiendo de esta forma que un
objeto permanente tenga varias copias en varios sitios conocidos.
En su forma ms literal, el formato de un URL es:
<protocolo>//<usuario>:<clave>@<id-mquina>:<puerto>/<ruta>
donde:
<protocolo> es el nombre no sensible a maysculas o minsculas del protocolo de la capa
de aplicacin utilizado para acceder al recurso; por ejemplo, HTTP.
<usuario>:<clave> es la autorizacin de acceso, en el caso de que sea requerida.
7

<id-mquina> es el nombre de dominio o direccin IP decimal.


<puerto> es el puerto para el protocolo de la capa de transporte del proceso que proporciona el servicio en la mquina remota.
<ruta> especifica la ruta dentro del sistema de ficheros de la mquina remota donde se
encuentra el recurso.
Servicio de nombres extensible
El servicio de nombres extensible (XNS) es un servicio de nombres de Internet gestionado
por la Organizacin XNS Public Trust Organization, una organizacin independiente. Permite
un esquema de nombrado con una direccin nica y universal para llevar a cabo todos los
tipos de comunicaciones: telfono, fax, web.... XNS est diseado para resolver una direccin
universal en cualquier otro tipo de direcciones de cualquier tipo de red de comunicaciones. Un
XNS es una cadena de caracteres: nombres personales, nombres de negocio y nombres generales,
cada uno de los cuales empieza por un nico carcter (=, @ y +, respectivamente).
Resolucin de nombres
Siempre que se utiliza un nombre simblico para identificar un recurso, el nombre debe
traducirse a la correspondiente direccin fsica. Al proceso de traduccin se le conoce como
resolucin de nombres, o simplemente bsqueda de nombres.
Se debe utilizar una base de datos que contenga las asociaciones entre nombres simblicos y
nombres fsicos. Los servidores DNS se encargan de realizar el servicio de bsqueda de nombres. Una autoridad central mantiene la base de datos de nombres y permite que la base de
datos se distribuya a travs de Internet a los servidores DNS.

1.7.

Conceptos bsicos de ingeniera del software

La ingeniera del software es la disciplina de informtica que aborda el proceso de desarrollo


de las aplicaciones. Algunos de sus conceptos bsicos son relevantes, y los introduciremos a
continuacin.
Programacin procedimental frente a programacin orientada a objetos
Hay dos clases de lenguajes de programacin: lenguaje procedimental y lenguaje orientado
a objetos.
Los lenguajes procedimentales (C), utilizan procedimientos para reducir la complejidad de
las tareas de la aplicacin. Una aplicacin puede implementarse utilizando un procedimiento
que lleve a cabo la entrada, otro para realizar la computacin, 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 como
los diferentes comportamientos del mismo. Los comportamientos se representan mediante los
mtodos.
UML
Un paso importante en la ingeniera del software es la produccin de artefactos, o documentos, para realizar el diseo conceptual de la aplicacin que se est desarrollando. El lenguaje de
modelado unificado (UML) proporciona un conjunto de comn de lenguaje y notaciones para
especificar, visualizar, construir y documentar los artefactos de los sistemas software.
En este resumen se utilizar ocasionalmente una de estas notaciones: los diagramas de clase
UML, para documentar las relaciones de algunas de las clases Java que aparecen en la presentacin. La Figura 2 presenta el subconjunto de diagramas de clase que utilizaremos.

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 de
datos se puede aplicar a las aplicaciones distribuidas. La Figura 3 presenta un ejemplo de dicha
arquitectura.

Figura 3: Arquitectura de las aplicaciones distribuidas.

Las funciones de una aplicacin distribuida se pueden clasificar en tres capas:


La capa de presentacin proporciona la interfaz de usuario.
La capa lgica de aplicacin proporciona la computacin necesaria para la aplicacin. Esta
capa tambin se llama capa lgica de negocio para las aplicaciones empresariales.
La capa de servicio proporciona los servicios necesarios para soportar las funciones de las
otras dos capas. Los servicios pueden incluir utilidades de acceso a los datos, servicios de
directorio para bsquedas de nombres, y comunicacin 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 componentes
son trminos asociados con la ingeniera del software para sistemas empresariales.
Un toolkit o framework es una coleccin de clases, herramientas y ejemplos de programacin. Por ejemplo, el toolkit JDK es una coleccin de herramientas para desarrollar programas
Java,
9

El desarrollo de software basado en componentes es una tcnica para la construccin de


sistemas software empresariales. Utilizando esta tcnica, el software se desarrolla y evoluciona
mediante la unin de componentes ya probados y reutilizables.

10

2.
2.1.

IPC - Comunicacin entre procesos


Un arquetipo de interfaz de programacin para comunicacin entre procesos

Para facilitar la comunicacin entre procesos se necesitan cuatro operaciones primitivas bsicas:
Enviar. Se invoca por el proceso emisor con el propsito de transmitir datos al proceso
receptor.
Recibir. Es invocada por el proceso receptor con el objetivo de aceptar datos de un proceso
emisor.
Conectar. Para mecanismos de comunicacin orientados a conexin deben existir operaciones que permitan establecer una conexin lgica entre el proceso que lo invoca y otro
proceso determinado.
Desconectar. Para mecanismos de comunicacin orientados a conexin, permite que una
conexin lgica sea liberada en ambos extremos de la comunicacin.

2.2.

Sincronizacin de eventos

Una de las mayores dificultades cuando se trabaja con mecanismos de comunicacin entre
procesos es que cada proceso involucrado se ejecuta de forma independiente sin que ninguno
de ellos sepa qu ocurre en el proceso en el otro extremo.
La forma ms sencilla que tiene un mecanismo de comunicacin de procesos para proporcionar sincronizacin de eventos es por medio de peticiones bloqueantes, que es la supresin de la
ejecucin del proceso hasta que la operacin invocada haya finalizado.
Durante su ejecucin, el proceso se suspende despus de que se invoque cada llamada bloqueante. Cada vez que se ejecuta una invocacin a una operacin bloqueante, la condicin de
bloqueo se inicia por las funcionalidades de comunicacin entre procesos en conjunto con el sistema operativo sobre el que se apoya. En el caso de que la operacin 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 intervencin
apropiadas.
Las operaciones bloqueantes a menudo se llaman operaciones sncronas. Como alternativa, las operaciones de comunicacin entre procesos tambin pueden ser asncronas o no bloqueantes. Una operacin asncrona invocada por un proceso no causar bloqueo, y se informar
posteriormente al proceso si la operacin se ha completado y si lo ha hecho con xito o no.

2.3.

Temporizadores e hilos de ejecucin

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 mximo de bloqueo. En segundo lugar,
un proceso puede lanzar otro proceso hijo o un hilo de ejecucin (thread) independiente para
invocar la operacin bloqueante, permitiendo de esta manera al hilo de ejecucin principal o al
proceso padre del programa seguir ejecutando otras tareas de procesamiento mientras el hilo de
ejecucin o proceso hijo se suspende.
Los temporizadores son importantes si la ejecucin de operaciones sncronas puede potencialmente dar como resultado un bloqueo indefinido.

2.4.

Interbloqueos y temporizadores

Otra causa de sufrir un bloqueo indefinido son los interbloqueos (deadblocks). Un interbloqueo puede causarse por una operacin invocada de forma no apropiada. La Figura 4 muestra
este caso. El proceso 1 ha invocado una operacin de recibir para recoger datos del proceso 2.
A la vez, el proceso 2 ha invocado otro recibir bloqueante cuando debera ser una operacin de
enviar lo ms apropiado. Cada proceso por su parte se encontrar suspendido indefinidamente
hasta que salte un temporizador o hasta que el sistema operativo aborte el proceso.
11

Figura 4: Un interbloqueo causado por operaciones bloqueantes.

2.5.

Representacin de datos

En el nivel fsico de una arquitectura de red (el nivel ms bajo), los datos se transmiten como
seales analgicas, las cuales representan un flujo binario. En el nivel de aplicacin, se necesita
una representacin ms compleja de los datos transmitidos con el objeto de dar soporte a la
representacin de tipos de datos y estructuras.
Si consideramos el caso simple de dos procesos, proceso 1 en el ordenador A y proceso 2 en
el ordenador B, donde el proceso 1 calcula un valor e invoca una operacin enviar para mandar
el valor al proceso 2, el cual a su vez invoca una operacin recibir para recoger dicho valor; y
todo hecho de acuerdo al protocolo establecido.
Si el ordenador A es una mquina de 32 bits que utiliza representacin big-endian y el ordenador B una mquina de 16 bits con representacin little-endian, supngase que el dato a transmitir
es de 32 bits y que es transmitido directamente desde el espacio de almacenamiento del proceso
1 al espacio reservado por el proceso 2. Entonces (1) 16 bits de los 32 enviados van a ser truncados ya que el tamao de un entero en el computador B es de slo 16 bits, y (2) el orden de
los bytes de la representacin de los enteros debe ser intercambiado de forma que se interprete
correctamente el mismo valor por parte del proceso receptor.
Los procesos participantes en una comunicacin deben tomar las medidas oportunas para
empaquetar e interpretar los datos de forma apropiada. Para nuestro ejemplo, hay tres esquemas
posibles:
1. Antes de invocar a la operacin enviar, el proceso 1 convierte el valor entero a 16 bits en
formato little-endian para el proceso 2.
2. El proceso 1 enva los datos en 32 bits y representacin big-endian. Tras recibir los datos, el
proceso 2 convierte el valor a su formato, 16 bits y little-endian.
3. Los procesos intercambian los datos atendiendo a una representacin externa: los datos se
van a enviar transformados a esa representacin y los datos recibidos se van a interpretar
con esa representacin para luego traducirlos a la representacin nativa.
El trmino empaquetamiento de datos (data marshaling) se usa en el contexto de los mecanismos
de comunicacin entre procesos para referirse a las transformaciones necesarias para transmitir
valores de datos o estructuras.
Debido a la complejidad existente, el empaquetado de objetos (datos y mtodos de un objeto
de algn lenguaje orientado a objetos como Java) implica un mayor reto que el del resto de
estructuras, por lo que se le ha dado un nombre especfico: serializacin de objetos.

2.6.

Codificacin de datos

Las aplicaciones distribuidas de propsito general necesitan un esquema universal, e independiente de plataforma, para codificar el intercambio de datos. Como se muestra en la Figura
5, hay estndares para la codificacin de datos disponibles a diferentes niveles de abstraccin.

12

Figura 5: Estndares de representacin de datos de red.

2.7.

Protocolos basados en texto

El empaquetamiento de datos es, en el caso ms simple, cuando se intercambian cadenas de


caracteres o texto codificado en una representacin de tipo ASCII. Tiene la ventaja adicional de
que puede ser fcilmente analizado por un programa y mostrado a un usuario humano. Estos
protocolos 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 peticin y espera una respuesta del otro extremo.
Posteriormente, puede ser enviada otra solicitud, esperndose de nuevo respuesta. El protocolo
se desarrolla basndose 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 secuencia


detallada de eventos y bloqueos durante la ejecucin de un protocolo. La Figura 6 es un diagrama
de 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 enviar
y recibir para intercambiar dos mensajes. El protocolo se puede extender hasta cualquier nmero
de turnos de intercambios con este patrn.

Figura 6: Un diagrama de eventos.

Tambin es esencial que los programas que implementan el protocolo estn escritos para

13

invocar las operaciones de enviar y recibir en el orden preestablecido, de otra forma pueden
quedarse bloqueados de forma indefinida.
La Figura 7 presenta, por medio de un diagrama de eventos, un protocolo HTTP. En su forma
ms bsica, HTTP es un protocolo basado en texto del tipo peticin-respuesta que utiliza slo un
turno de intercambio de mensajes. Un servidor web es un proceso que escucha constantemente
peticiones realizadas desde procesos navegadores.

Figura 7: Diagrama de eventos de una sesin HTTP.

Una forma simplificada de este diagrama, denominada diagrama de secuencia y parte de


la notacin UML, se usa ms habitualmente para denotar la comunicacin entre procesos. En
un diagrama de secuencia, no se diferencia entre estados de bloqueo y ejecucin. Cada mensaje
intercambiado se representa con una lnea 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 sesin HTTP de
ejemplo. Por medio de un cliente telnet se puede conectar a un servidor web e introducir el texto
de una peticin HTTP a mano.

2.10.

Comunicacin entre procesos orientada y no orientada a conexin

Por medio de un mecanismo de IPC orientado a conexin, dos procesos establecen una conexin y posteriormente, insertan datos en extraen datos desde dicha conexin. Una vez que la
conexin es establecida, no es necesaria la identificacin de emisor y receptor.
Para el caso de una IPC no orientada a conexin, los datos son intercambiados por medio de
paquetes independientes cada uno de los cuales necesita explcitamente la direccin del receptor.

2.11.

Evolucin de los paradigmas de comunicacin entre procesos.

Veremos diferentes modelos, o paradigmas, por medio de los cuales la comunicacin entre
procesos se proporciona al programador que quiere utilizar una IPC en su programa.
En el nivel menos abstracto, la comunicacin entre procesos implica la transmisin de ristras
binarias sobre una conexin, serie o paralelo. Este paradigma puede ser vlido para el desarrollo
del software de un driver de red. No se ver en este resumen.
14

Figura 9: El dilogo durante una sesin HTTP.

El siguiente nivel es un paradigma bien conocido, denominado interfaz de programacin de


aplicaciones de sockets. (el API de sockets). Por medio del paradigma de sockets, dos procesos
intercambian datos por medio de una estructura lgica denominada socket, habiendo uno de
cada 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 Captulo 3.
Los paradigmas de llamadas a procedimientos remotos o de invocacin de mtodos remotos proporcionan una mayor abstraccin, permitiendo al proceso realizar llamadas a procedimientos o la invocacin de mtodos de un proceso remoto, con la transmisin de datos como
argumentos o valores de resultado. Se ver en el Captulo 8.

15

3.
3.1.

Paradigmas de computacin distribuida


Paradigmas y abstraccin

Abstraccin
La abstraccin es la idea de encapsulacin, o de ocultamiento de detalles. La abstraccin se
materializa en proporcionar herramientas o funcionalidades que permitan el desarrollo de software sin que el programador tenga que conocer las complejidades subyacentes. Por ejemplo, se
utilizan compiladores para abstraerse del detalle de los lenguajes mquina, y los programadores
Java utilizan el paquete AWT para desarrollar rpidamente interfaces grficas.
Paradigmas
El diccionario Webster define la palabra paradigma como un patrn, ejemplo o modelo.
Es til identificar los patrones o modelos bsicos y clasificar los detalles de acuerdo con estos
modelos. Este captulo busca presentar una clasificacin de los paradigmas sobre aplicaciones
distribuidas. Los paradigmas se van a presentar ordenados basndose en su nivel de abstraccin,
como se muestra en la Figura 10.

Figura 10: Los paradigmas de computacin distribuida y su nivel de abstraccin.

3.2.

Una aplicacin de ejemplo

A travs del resto de este captulo, se usar una misma aplicacin para estudiar cmo se
aplica cada uno de los paradigmas.
Se trata de un sistema de subastas on-line. (Las implementaciones descritas intencionadamente ignoran detalles de la aplicacin real). Se simplificar el sistema hasta el punto de tratar slo
un objeto a subastar en cada sesin. Durante cada sesin de subasta, un objeto est abierto a
pujas emitidas por los participantes en la subasta. Al final de la sesin, el subastador anuncia el
resultado. Se va a centrar la atencin en los aspectos de computacin distribuida de la capa de
servicio (esto es, en el nivel de servicio subyacente que da soporte al resto de niveles superiores)
de la arquitectura de la aplicacin.

3.3.

Paradigmas para aplicaciones distribuidas

Paso de mensajes
La aproximacin ms bsica a la comunicacin entre procesos es el paso de mensajes. Los
datos 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 receptor, que procesa la peticin y enva un mensaje como respuesta. Las operaciones bsicas
necesarias para dar soporte al paradigma de paso de mensajes son enviar y recibir. Para comunicaciones orientadas a conexin, tambin se necesitan las operaciones conectar y desconectar. Las
operaciones sirven para encapsular el detalle de la comunicacin a nivel del sistema operativo,
de forma que el programador puede hacer uso de operaciones para enviar y recibir mensajes sin
preocuparse por el detalle subyacente.

16

La interfaz de programacin de aplicaciones de sockets se basa en este paradigma. Usando


un socket, dos procesos pueden intercambiarse datos de la siguiente forma: un emisor escribe o
inserta 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. Un
proceso, el servidor, interpreta el papel de proveedor de servicios, esperando de forma pasiva la
llegada de peticiones. El otro, el cliente, invoca determinadas peticiones al servidor y aguarda
sus respuestas. La Figura 11 ilustra este paradigma.

Figura 11: El paradigma cliente-servidor.

El modelo cliente-servidor proporciona una abstraccin eficiente para facilitar servicios de


red. Las operaciones necesarias incluyen aquellas que permiten a un proceso servidor escuchar
y aceptar peticiones, y a un cliente solicitar dichas peticiones y aceptar las respuestas. La sincronizacin de eventos se simplifica: el proceso servidor espera peticiones, y el cliente en su turno
espera las respuestas.
Cada participante, as como el programa de subastas, asumen a la vez el papel de cliente y
servidor, de la siguiente forma:
Para el control de la sesin:
Como servidor, un participante espera escuchar el anuncio del subastador (1) cuando comience la sesin, (2) en el momento en el que se produzca un cambio en la puja mxima,
y (3) cuando la sesin termine.
Como servidor, el subastador enva una peticin que anuncia los tres tipos de eventos antes
comentados.
Para la aceptacin de pujas:
Como servidor, un participante enva una nueva puja a un servidor.
Como cliente, un subastador acepta nuevas pujas y actualiza la puja mxima.
Paradigma de igual a igual peer-to-peer
En el paradigma cliente-servidor, no se da soporte para que el proceso servidor inicie la
comunicacin.
En el paradigma peer-to-peer, los procesos participantes interpretan los mismos papeles,
con idnticas capacidades y responsabilidades. Cada participante puede solicitar una peticin a
cualquier otro participante y recibir una respuesta.
El paradigma peer-to-peer resulta ms apropiado para aplicaciones como mensajera instantnea, transferencia de ficheros, vdeo-conferencia, y trabajo colaborativo. Tambin es posible que
una aplicacin se base simultneamente en los modelos cliente-servidor y peer-to-peer. Napster.com utiliza un servidor como directorio adems de la comunicacin peer-to-peer.

17

Este paradigma se puede implementar por medio de bibliotecas que proporcionen herramientas para el paso de mensajes.
La implementacin de nuestro sistema de subastas puede simplificarse sustancialmente aplicando peer-to-peer. Un participante puede conectarse al subastador directamente para registrarse
en la subasta. El subastador posteriormente contacta con cada uno de los participantes para iniciar la sesin de subasta, durante la cual cada uno de los participantes individualmente pueden
obtener el estado y realizar pujas. Al concluir la subasta, el subastador notifica al ganador, y el
resto 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), (Figura
12) es una elaboracin del paradigma bsico del paso de mensajes.

Figura 12: El paradigma de sistema de mensajes.

En este paradigma, un sistema de mensajes sirve de intermediario entre procesos separados


e independientes. El sistema de mensajes acta como un conmutador para mensajes, a travs
del cual los procesos intercambian mensajes asncronamente, de forma desacoplada. Un emisor
deposita un mensaje en el sistema de mensajes, el cual redirige el mismo a la cola de mensajes
asociada a dicho receptor. Una vez que se ha enviado, el emisor queda liberado para que realice
cualquier otra tarea.
Modelo de mensajes punto a punto
En este modelo, un sistema de mensajes redirige un mensaje desde el emisot hasta la cola de
mensajes del receptor. El middleware proporciona un depsito de los mensajes que permite que
el envo y la recepcin estn desacoplados. Un proceso receptor extrae los mensajes de su cola
de mensajes y procesa cada mensaje de forma correspondiente.
El paradigma de mensajes punto a punto proporciona una abstraccin adicional para operaciones asncronas.
La implementacin de nuestro sistema de subastas es la misma que con el modelo bsico de
paso de mensajes. La nica diferencia es que los mensajes se canalizan por medio del middleware.
Modelo de mensajes publicacin/suscripcin
En este modelo, cada mensaje se asocia con un determinado tema o evento. Las aplicaciones
interesadas en el suceso de un especfico evento se pueden suscribir a los mensajes de dicho
evento. Cuando el evento que se aguarda ocurre, el proceso publica un mensaje anunciando
el evento o asunto. El middleware del sistema de mensajes distribuye el mensaje a todos los
suscriptores.
El modelo de mensajes publicacin/suscripcin ofrece una potente abstraccin para multidifusin o comunicacin en grupo.
La implementacin de nuestro sistema de subastas se realizara de la siguiente forma:
Cada participante se suscribe a los mensajes del evento comienzo-subasta.
El subastador anuncia el comienzo de la sesin de subasta enviando un mensaje de evento
comienzo-subasta.

18

Middleware
hace referencia al software
que
acta
como intermediario
entre
procesos independientes.
Los sistemas
de mensajes
son unos de
los tipos de
middleware, los
ORB o broker
de peticiones
son otros.

Tras recibir el evento de comienzo-subasta, cada participante se suscribe a los mensajes del
evento fin-subastaEl 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 sesin, el subastador lanzar un mensaje fin-subasta para informar a todos los
participantes del resultado.
Modelo de llamadas a procedimientos remotos
Cuando las aplicaciones crecen en complejidad, resulta necesario un nivel de abstraccin
mayor para la programacin distribuida. Resultara deseable tener un paradigma que permitiera
que el software distribuido se programase de una manera similar a las aplicaciones convencionales que se ejecutan sobre un nico procesador. El modelo de llamada a procedimientos remotos
(RPC) proporciona dicha abstraccin. La comunicacin entre dos procesos se realiza utilizando
un concepto similar al de una llamada a un procedimiento local.
En un programa que slo implica a un nico proceso, una llamada a un procedimiento del
tipo func(arg1, arg2) implica un salto en flujo de ejecucin al cdigo de dicho procedimiento.
Una llamada a un procedimiento remoto implica dos procesos independientes, que pueden
residir en mquinas diferentes, y dispara una accin predefinida en un procedimiento proporcionado por uno de los procesos. Al finalizar el procedimiento, el proceso devuelve un valor al
proceso 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 siguiente forma:
El programa de subastas proporciona un procedimiento remoto para que cada participante
se registre y otro procedimiento para que stos hagan pujas.
Cada programa participante proporciona los siguientes procedimientos remotos: (1) el que
permite al subastador llamar al participante para anunciar el comienzo de una sesin, (2) el
que permite al subastador informar al participante de la puja ms alta, y (3) el que permite
que el subastador anuncie el final de la sesin.
Paradigma de objetos distribuidos
Las aplicaciones acceden a objetos distribuidos sobre una red. Los objetos proporcionan mtodos, a travs de cuya invocacin una aplicacin obtiene acceso a los servicios. Varios paradigmas
se basan en la idea de objetos distribuidos.

19

Invocacin de mtodos remotos


La invocacin de mtodos remotos (RMI) es el equivalente en orientacin a objetos de las llamadas a procedimientos remotos. En este modelo, un proceso invoca mtodos de un objeto, el cual
reside en un ordenador remoto.
Los argumentos se pueden pasar con la invocacin, y se puede devolver un valor cuando el
mtodo ha concluido.
La implementacin de nuestro sistema de subastas es esencialmente la misma que con RPC,
la excepcin es que los mtodos de los objetos reemplazan los procedimientos.
Paradigma basado en Object Request Broker
En el paradigma basado en Object Request Broker, un proceso solicita una peticin a un ORB,
el cual redirige la peticin al objeto apropiado que proporciona dicho servicio. El paradigma
se parece bastante al modelo de invocacin de mtodos remotos. La diferencia es que el ORB
en este paradigma funciona como middleware, permitiendo a una aplicacin, como solicitante de
un objeto, acceder potencialmente a varios objetos remotos (o locales). El ORB puede funcionar
tambin como mediador para diferentes objetos heterogneos, permitiendo la interaccin entre
objetos implementados usando diferentes API y/o ejecutando sobre diferentes plataformas.
La implementacin del sistema de subastas usando un ORB es similar a la que usa RMI. Con
la excepcin 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 subastador
para registrarse para la sesin y hacer pujas. A travs del ORB, el subastador invoca los mtodos
de cada participante para anunciar el comienzo de la sesin y actualizar el estado de las pujas,
y anunciar el final de la sesin.
Espacio de objetos
El paradigma de Espacio de Objetos asume la existencia de entidades lgicas conocidas como
espacio de objetos. Los participantes en una aplicacin convergen en un espacio de objetos
comn. Un suministrador coloca objetos como entidades dentro de un espacio de objetos, y los
solicitantes que se suscriben al espacio pueden acceder a dichas entidades.
Adems del grado de abstraccin proporcionado por los otros paradigmas, proporciona un
espacio virtual o sala de reunin entre suministradores y solicitantes de recursos de red, como
objetos. Esta abstraccin oculta los detalles implicados en la bsqueda de recursos u objetos que
son necesarios en paradigmas como la invocacin de mtodos remotos, ORB, o servicios de red.
Adems, la exclusin mutua es inherente al paradigma, debido a que un objeto en el espacio
puede slo ser usado por un participante a la vez.
Para el sistema de subastas, todos los participantes as como el suministrador de servicios se
suscribiran al mismo espacio de objetos. Cada participante depositara un objeto en el espacio
de objetos para registrarse en la sesin y para ser notificado del comienzo de la misma. Al comienzo de la sesin, el subastador deposita otro objeto en el espacio de objetos. El objeto contiene
informacin sobre el elemento a subastar as como el histrico de las pujas. Un participante que
desee realizar una puja tomar el objeto del espacio y, si as lo quiere, aadir una nueva puja en
el objeto antes de devolverlo al espacio de objetos. Al final de la sesin el subastador retirar el
objeto del espacio y, si as lo quiere, aadir una nueva puja en el objeto antes de devolverlo al
espacio de objetos. Al final de la sesin el subastador retirar el objeto del espacio y contactar
con el participante con la mayor puja.
Paradigma de agentes mviles
Un agente mvil es un programa u objeto transportable. En este paradigma, un agente se
lanza desde un determinado ordenador. El agente entonces viaja de forma autnoma de un
ordenador a otro de acuerdo con un itinerario que posee. En cada parada, el agente accede a los
recursos o servicios necesarios y realiza las tareas correspondientes para completar su misin.
El paradigma ofrece la abstraccin de programa u objeto transportable. En lugar de intercambio de mensajes, los datos son transportados por el programa/objeto mientras el propio
objeto se transfiere entre los participantes.
Proporciona una novedosa forma de implementar nuestro sistema de subastas. En comienzo,
cada participante lanza un agente mvil hacia el subastador. El agente transporta la identidad,

20

incluyendo la direccin de red, del participante al que representa. Una vez que la sesin ha
comenzado el subastador lanza un agente mvil que transporta el itinerario de los participantes,
as como la mayor puja. El agente mvil circula entre los participantes y el subastador hasta que
finalice la sesin, en cuyo instante el subastador lanza el agente para dar un recorrido ms entre
todos los participantes para comunicar el resultado.
Paradigma de servicios de red
En este paradigma los proveedores de servicios se registran en los servidores de directorio
de una red. Un proceso que desee un servicio particular contacta con el servidor de directorio
en tiempo de ejecucin, y, si el servicio est disponible, al proceso se le dar una referencia a
dicho servicio. Usando esta referencia, el proceso interactuar con el servicio.
Es esencialmente una extensin del paradigma de invocacin de mtodos remotos. La diferencia es que los objetos de servicio se registran en un directorio global. Idealmente, los servicios
se pueden registrar y localizar usando un identificador nico global, en cuyo caso el paradigma
ofrece un nivel de abstraccin extra: transparencia de localizacin.
La implementacin de nuestro sistema de subastas es la misma que bajo el paradigma RMI
excepto que el subastador se registra en el servicio de directorio, permitiendo que los participantes lo localicen.
Paradigma de aplicaciones colaborativas (groupware)
En este modelo para trabajo cooperativo basado en ordenador, los procesos participan en
grupo en una sesin colaborativa. Cada proceso participante puede hacer contribuciones a todos
o parte del grupo. Los procesos pueden hacer eso usando multidifusin para enviar los datos o
usar pizarras o tablones virtuales, los cuales permiten a cada participante leer y escribir datos
sobre una visualizacin 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 mensajes, el subastador iniciar un grupo, al que se incorporarn los participantes interesados. Al
comienzo de la sesin, el subastador difundir un mensaje de multidifusin anunciando el comienzo. Durante la sesin, cada puja es un mensaje de multidifusin a todos los participantes
de forma que cada uno puede independientemente acceder al estado de la subasta. Finalmente, el subastador termina la sesin por medio de un mensaje de multidifusin anunciando el
resultado.
Si usamos el paradigma basado en pizarra, el subastador y los participantes comparten una
pizarra virtual. El subastador comienza el proceso de puja escribiendo un anuncio sobre la
pizarra. Posteriormente, cada participante puede realizar una puja escribindola en la pizarra.
Finalmente, el subastador termina la sesin escribiendo el anuncio final.

3.4.

Comparativa

Una misma aplicacin se puede implementar usando cualquiera de los paradigmas. Cmo
un desarrollador de software puede decidir la ms apropiada para una tarea dada?
Uno debe tener cuidado con lo que ofrece cada una de las diferentes alternativas. Es suficiente
decir que cada paradigma o herramienta tiene alguna ventaja sobre los otros.
21

Nivel de abstraccin frente a sobrecarga


La Figura 15 muestra los paradigmas que se han visto y sus niveles de abstraccin correspondientes. El desarrollo de una aplicacin altamente compleja se puede ver muy ayudado por
una herramienta que ofrece un gran nivel de abstraccin. Pero la abstraccin tiene un precio: la
sobrecarga.

Figura 15: Los paradigmas y los niveles de abstraccin.

Una aplicacin escrita usando RMI requerir ms recursos del sistema y tardar ms en
ejecutar que otra igual que se comunicase por medio del API de sockets. Por otro lado, RMI y
otras herramientas que proporcionan mayor nivel de abstraccin permiten que una aplicacin se
desarrolle ms rpidamente.
Escalabilidad
La complejidad de una aplicacin distribuida se incrementa significativamente cuando el
nmero de participantes se incrementa. En la aplicacin de ejemplo, el subastador debe manejar
las direcciones de los participantes de forma que pueda anunciar el comienzo y final de la sesin.
Adems, el subastador tiene que contactar repetidas veces con los participantes para notificarles
la puja ms alta. La complejidad crece cuando crece el nmero de participantes.
Con un conjunto de herramientas de un paradigma de alto nivel, la complejidad de gestionar
los participantes la realiza el sistema. Una aplicacin as implementada se puede acomodar a un
incremento en el nmero de participantes sin una complejidad adicional.
Soporte multi-plataforma
Los paradigmas son inherentemente independientes de la plataforma. Las herramientas basadas en los paradigmas, por otro lado, pueden ser dependientes de la plataforma. Una herramienta que soporte plataformas heterogneas necesariamente incrementa la complejidad, si se
compara con una que soporte una nica plataforma.
Muchas de las tecnologas Java, incluida el API Java RMI y los JavaSpaces, por omisin slo
ejecutan sobre mquinas virtuales Java.
Por contraste, CORBA es una arquitectura diseada para dar soporte multi-plataforma; de
forma que las herramientas basadas en esta tecnologa pueden soportar programas escritos en
diversos lenguajes y tambin procesos ejecutando sobre distintas plataformas.

22

El API de sockets

4.

Este captulo introduce la primera herramienta de programacin para implementar comunicaciones entre procesos: el API de sockets.
El API de sockets es un mecanismo que proporciona un nivel bajo de abstraccin para IPC.

4.1.

Antecedentes

El API de sockets aparece por por primera vez a principios de la dcada de los 80 como
una biblioteca de programacin que proporcionaba la funcionalidad de IPC en una versin del
sistema operativo UNIX (BSD).
Java proporciona el API de sockets como parte de las clases bsicas del lenguaje. Todas las
interfaces de programacin de sockets comparten el mismo modelo de paso de mensajes y una
sintaxis muy similar. En este captulo usaremos como caso representativo el API de sockets de
Java.

4.2.

La metfora del socket en IPC

Inspirndose en la terminologa de la telefona, el diseador del API de sockets ha proporcionado una construccin de programacin denominada socket. Cuando un proceso desea comunicarse con otro, debe crear una instancia de tal construccin. Sin embargo, a diferencia de la
telefona primitiva, la comunicacin entre los interlocutores puede ser orientada a conexin o
sin conexin.

4.3.

El API de sockets datagrama

Hay dos protocolos fundamentales en el nivel de transporte de la arquitectura de Internet: el


protocolo de datagrama de usuario (UDP) y el protocolo de control de transmisin (TCP).
El protocolo de datagrama de usuario (UDP) permite que un paquete se transporte utilizando comunicaciones sin conexin. El paquete de datos transportado de esta manera se denomina
datagrama. Cada datagrama es dirigido y transportado individualmente y puede llegar al receptor en cualquier orden.
El protocolo de control de transmisin (TCP) est orientado a conexin y transporta un flujo
de datos sobre una conexin lgica establecida entre el emisor y el receptor. Se garantiza que los
datos mandados van a ser recibidos en el mismo orden que se enviaron.
El API de sockets de Java proporciona construcciones de programacin de sockets que hacen
uso tanto del protocolo UDP como TCP. Los sockets que utilizan UDP son conocidos como sockets
datagrama, mientras que los que usan TCP se denominan sockets stream.
El socket datagrama sin conexin
Los sockets datagrama pueden dar soporte tanto a una comunicacin sin conexin como a
una orientada a conexin en el nivel de aplicacin (vase la Figura 16). Se debe a que el soporte
en tiempo de ejecucin del API de sockets puede crear y mantener conexiones lgicas para los
datagramas intercambiados entre dos procesos, como se mostrar en la prxima seccin.
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 objeto
DatagramSocket, o un socket para abreviar. Se dice que cada socket est enlazado a un puerto UDP
de la mquina que es local al proceso.
Para mandar un datagrama a otro proceso, un proceso debe crear un objeto que representa
el datagrama en s mismo. Este objeto puede crearse instanciando un objeto DatagramPacket
que englobe (1) una referencia a un vector de octetos que contenga los datos de la carga, y (2)
la direccin de destino. Una vez que se crea el objeto DatagramPacket y en l se incluyen los
datos de la carga y del destino, el proceso emisor realiza una llamada al mtodo send del objeto
DatagramSocket, especificando una referencia al objeto DatagramPacket como argumento.
23

Figura 16: Socket datagrama sin conexin y orientado a conexin.

En el proceso receptor, tambin se debe instanciar un objeto DatagramSocket y enlazarlo a un


puerto local; el nmero de puerto debe coincidir con el especificado en el paquete datagrama del
emisor. Para recibir los datagramas enviados al socket, el proceso crea un objeto DatagramPacket
que hace referencia a un vector de octetos y llama a un mdulo receive de su objeto DatagramSocket, especificando como argumento una referencia al objeto DatagramPacket.
Con los sockets sin conexin, un socket enlazado a un proceso puede utilizarse para mandar
datagramas a diferentes destinos. Es tambin posible que mltiples procesos manden simultneamente datagramas al mismo socket enlazado a un proceso receptor.
La Tabla 4.1 resume los mtodos principales y los constructores de la clase DatagramPacket,
mientras que la Tabla 4.2 recopila los de la clase DatagramSocket (hay muchos ms mtodos que
no se presentan en estas tablas).
Tabla 4.1: Mtodos principales de la clase DatagramPacket.

Mtodo/Constructor

Descripcin

DatagramPacket(byte[] almacn, int longitud)

Construye un paquete datagrama para recibir paquetes de


longitud longitud; los datos recibidos se almacenarn en el vector
de octetos asociado a almacn.

DatagramPacket(byte[] almacn, int longitud,


InetAddress direccin, int puerto)

Construye un paquete datagrama para enviar paquetes de


longitud longitud al socket enlazado al nmero de puerto y a la
mquina especificados; los datos se almacenan en el vector de
octetos asociado a almacn.

DatagramSocket()

Construye un socket datagrama y lo enlaza a cualquier puerto


disponible de la mquina local; este constructor lo puede utilizar
un proceso que manda datos y no necesita recibirlos.

Sincronizacin de eventos en los sockets datagrama


En las interfaces de programacin de sockets bsicas, las operaciones send son no bloqueantes,
mientras que las operaciones receive son bloqueantes. Para evitar un bloqueo indefinido, el
proceso receptor puede utilizar el mtodo setSoTimeout para fijar un plazo mximo de tiempo
de bloqueo. Si no se recibe ningn dato durante este plazo se activar una excepcin Java (una
java.io.InterruptedIOException) que puede capturarse en el cdigo.
Ejemplo 1. Los Listados 4 y 5 ilustran el cdigo de dos programas que utilizan sockets datagrama para intercambiar una nica cadena de datos. El emisor crea un paquete datagrama que
contiene una direccin de destino, mientras que el paquete datagrama del receptor no incluye
24

Tabla 4.2: Mtodos principales de la clase DatagramSocket.

Mtodo/Constructor

Descripcin

DatagramSocket(int puerto)

Construye un socket datagrama y lo enlaza al puerto especificado


en la mquina local; este nmero de puerto se puede especificar
despus 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)

Enva un paquete datagrama utilizando este socket.

void setSoTimeout(int plazo)

Fija un plazo mximo de espera en milisegundos para las


operaciones de recepcin bloqueantes realizadas con este socket.

una direccin de destino. El socket del emisor se enlaza a un nmero de puerto no especificado
para que el emisor pueda especificar este nmero de puerto en su datagrama como destino. Por
simplicidad los programas de ejemplo utilizan una sintaxis rudimentaria para manejar excepciones.
Listado 4: Ejemplo1Emisor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import java.net.*;
import java.io.*;
/**
* Mandar un mensaje utilizando un socket datagrama sin conexin.
* Se esperan tres argumentos:
* <nombre del dominio o direccin IP del receptor>
* <nmero de puerto del socket del receptor>
* <mensaje para mandar>
*/
public class Ejemplo1Emisor {
public static void main(String[] args) {
if(args.length != 3)
System.out.println("Se requieren 3 argumentos");
else {
try {
InetAddress maquinaReceptora = InetAddress.getByName(args[0]);
int puertoReceptor = Integer.parseInt(args[1]);
String mensaje = args[2];
DatagramSocket miSocket = new DatagramSocket();
byte[] almacen = mensaje.getBytes();
DatagramPacket datagrama = new DatagramPacket(almacen, almacen.length,
maquinaReceptora, puertoReceptor);
miSocket.send(datagrama);
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //fin class

Listado 5: Ejemplo1Receptor.java
1
2
3
4
5
6
7
8
9
10

import java.net.*;
import java.io.*;
/**
* Recibir un mensaje utilizando un socket datagrama sin conexin.
* Se espera un argumento:
* <nmero de puerto del socket del receptor>
*/
public class Ejemplo1Receptor {
public static void main(String[] args) {

25

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

if(args.length != 1)
System.out.println("Se requiere 1 argumento");
else {
int puerto = Integer.parseInt(args[0]);
final int MAX_LON = 10; //Longitud mxima en octetos admitida
try {
DatagramSocket miSocket = new DatagramSocket(puerto);
byte[] almacen = new byte[MAX_LON];
DatagramPacket datagrama = new DatagramPacket(almacen, MAX_LON);
miSocket.receive(datagrama);
String mensaje = new String(almacen);
System.out.println(mensaje);
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} // fin catch
} //fin else
} //fin main
} //fin class

Hay algunas anomalas en el comportamiento de los sockets datagrama sin conexin:


Si se manda un datagrama a un socket que el receptor todava no ha creado, es posible que
el datagrama sea desechado. Se puede experimentar con este comportamiento arrancando
Ejemplo1Emisor antes de ejecutar Ejemplo1Receptor.
Si el receptor especifica una zona de almacenamiento para el datagrama con un tamao n,
un mensaje recibido con un tamao en octetos mayor que n se truncar.
Ejemplo 2. Es posible hacer la comunicacin dplex o bidireccional. Para hacerlo as, Ejemplo1Emisor necesitar enlazar su socket a una direccin especfica para que Ejemplo1Receptor pueda mandar datagramas a esa direccin.
El cdigo de ejemplo en los Listados 6, 7 y 8 ilustra cmo puede llevarse a cabo la comunicacin dplex. Se crea una clase llamada MiSocketDatagrama como una subclase de DatagramSocket,
con dos mtodos de instancia para mandar y recibir un mensaje, respectivamente. El programa Ejemplo2EmisorReceptor instancia un objeto MiSocketDatagrama, a continuacin, llama a su
mtodo enviaMensaje, seguido por una llamada a su mtodo recibeMensaje. El programa Ejemplo2ReceptorEmisor instancia un objeto MiSocketDatagrama, a continuacin, llama a su mtodo
recibeMensaje, seguido por una llamada a su mtodo enviaMensaje.
Listado 6: MiSocketDatagrama.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

import java.net.*;
import java.io.*;
/**
* Una subclase de DatagramSocket que enva y recibe mensajes.
*/
public class MiSocketDatagrama extends DatagramSocket {
static final int MAX_LON = 10;
MiSocketDatagrama(int numPuerto) throws SocketException {
super(numPuerto);
}
public void enviaMensaje(InetAddress maquinaReceptora, int puertoReceptor, String
mensaje) throws IOException {
byte[] almacenEnvio = mensaje.getBytes();
DatagramPacket datagrama = new DatagramPacket(almacenEnvio, almacenEnvio.length
, maquinaReceptora, puertoReceptor);
this.send(datagrama);
}
public String recibeMensaje() throws IOException {
byte[] almacenRecepcion = new byte[MAX_LON];
DatagramPacket datagrama = new DatagramPacket(almacenRecepcion, MAX_LON);
this.receive(datagrama);
String mensaje = new String(almacenRecepcion);
return mensaje;

26

26
27

}
} //fin class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import java.net.*;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

import java.net.*;

Listado 7: Ejemplo2EmisorReceptor.java

/**
* Aplicacin que manda y despus recibe un mensaje utilizando un socket datagrama
* sin conexin.
* Se esperan cuatro argumentos:
* <nombre de dominio o direccin IP del receptor>
* <nmero de puerto del socket datagrama del receptor>
* <nmero de puerto del socket datagrama de este proceso>
* <mensaje, una cadena, para mandar>
*/
public class Ejemplo2EmisorReceptor {
public static void main(String[] args) {
if(args.length != 4)
System.out.println("Se requieren 4 argumentos");
else {
try {
InetAddress maquinaReceptora = InetAddress.getByName(args[0]);
int puertoReceptor = Integer.parseInt(args[1]);
int miPuerto = Integer.parseInt(args[2]);
String mensaje = args[3];
MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);
miSocket.enviaMensaje(maquinaReceptora, puertoReceptor, mensaje);
System.out.println(miSocket.recibeMensaje());
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //fin class

Listado 8: Ejemplo2ReceptorEmisor.java

/**
* Aplicacin que recibe un mensaje y despus lo manda utilizando un socket datagrama
* sin conexin.
* Se esperan cuatro argumentos:
* <nombre de dominio o direccin IP del receptor>
* <nmero de puerto del socket datagrama del receptor>
* <nmero de puerto del socket datagrama de este proceso>
* <mensaje, una cadena, para mandar>
*/
public class Ejemplo2ReceptorEmisor {
public static void main(String[] args) {
if(args.length != 4)
System.out.println("Se requieren 4 argumentos");
else {
try {
InetAddress maquinaReceptora = InetAddress.getByName(args[0]);
int puertoReceptor = Integer.parseInt(args[1]);
int miPuerto = Integer.parseInt(args[2]);
String mensaje = args[3];
MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);
System.out.println(miSocket.recibeMensaje());
miSocket.enviaMensaje(maquinaReceptora, puertoReceptor, mensaje);
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main

27

32

} //fin class

Es tambin posible que mltiples procesos entablen una comunicacin sin conexin de esta
manera; es decir, se puede aadir un tercer proceso que tambin tenga un socket datagrama, de
forma que pueda tambin mandar y recibir de los otros procesos.
El API de sockets datagrama orientados a conexin
Es poco comn emplear sockets datagrama para comunicaciones orientadas a conexin; la
conexin proporcionada por esta API es rudimentaria y tpicamente insuficiente para las aplicaciones.
La Tabla 4.3 describe dos mtodos de la clase DatagramSocket que permiten crear y terminar
una conexin. Para realizar una conexin con un socket, se especifica la direccin de un socket
remoto. Una vez hecha tal conexin, el socket se utiliza para intercambiar paquetes de datagrama
con el socket remoto. Si se mandan los datos al socket desde una fuente que no corresponde con
el socket remoto conectado, los datos se ignorarn. As, una vez que se asocia una conexin a un
socket datagrama, este socket no estar disponible para comunicarse con otro socket hasta que la
conexin se termine. La conexin es unilateral; esto es, slo se impone en un extremo. El socket
en el otro lado est disponible para mandar y recibir datos a otros sockets, a menos que se realice
una conexin con este socket.
Tabla 4.3: Llamadas de mtodo para un socket datagrama orientado a conexin.

Mtodo/Constructor

Descripcin

void connect(InetAddress direccion, int puerto)

Crea una conexin lgica entre este socket y un socket en la


direccin y puerto remotos.

void disconnect()

Termina la conexin actual, si existe, de este socket.

Ejemplo 3. El cdigo mostrado en los Listados 9 y 10 ilustra la sintaxis de uso de los sockets
datagrama orientados a conexin. En Ejemplo3Emisor.java, se crea una conexin entre el socket
datagrama del proceso emisor y el del proceso receptor. Ntese que la conexin se hace en
ambos lados. Una vez que se establece mutuamente una conexin, cada proceso est obligado a
utilizar su socket para la IPC con otro proceso (esto no prohbe a cada proceso crear otra conexin
utilizando otro socket). El emisor manda sucesivamente por la conexin 10 copias del mismo
mensaje. En el proceso receptor, se visualiza inmediatamente cada uno de los diez mensajes
recibidos. El proceso receptor despus manda un nico mensaje de vuelta al proceso emisor
para ilustrar que la conexin permite una comunicacin bidireccional.
Listado 9: Ejemplo3Emisor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

import java.net.*;
/**
* Aplicacin que utiliza un socket datagrama orientado a conexin para mandar
* mltiples mensajes, y despus recibe uno.
* Se esperan cuatro argumentos:
* <nombre de dominio o direccin IP del receptor>
* <nmero de puerto del socket datagrama del otro proceso>
* <nmero de puerto del socket datagrama de este proceso>
* <mensaje, una cadena, para mandar>
*/
public class Ejemplo3Emisor {
public static void main(String[] args) {
if(args.length != 4)
System.out.println("Se requieren 4 argumentos");
else {
try {
InetAddress maquinaReceptora = InetAddress.getByName(args[0]);
int puertoReceptor = Integer.parseInt(args[1]);
int miPuerto = Integer.parseInt(args[2]);
String mensaje = args[3];
MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);
miSocket.connect(maquinaReceptora, puertoReceptor);

28

25
26
27
28
29
30
31
32
33
34
35
36
37
38

for(int i=0; i<10; i++)


miSocket.enviaMensaje(maquinaReceptora, puertoReceptor, mensaje);
System.out.println(miSocket.recibeMensaje());
miSocket.disconnect();
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //fin class

Listado 10: Ejemplo3Receptor.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

import java.net.*;
/**
* Aplicacin que utiliza un socket datagrama orientado a conexin para recibir
* mltiples mensajes, y despus enva uno.
* Se esperan cuatro argumentos:
* <nombre de dominio o direccin IP del emisor>
* <nmero de puerto del socket datagrama del emisor>
* <nmero de puerto del socket datagrama de este proceso>
* <mensaje, una cadena, para mandar>
*/
public class Ejemplo3Receptor {
public static void main(String[] args) {
if(args != 4)
System.out.println("Se esperan 4 argumentos");
else {
try {
InetAddress maquinaEmisora = InetAddress.getByName(args[0]);
int puertoEmisor = Integer.parseInt(args[1]);
int miPuerto = Integer.parseInt(args[2]);
String mensaje = args[3];
MiSocketDatagrama miSocket = new MiSocketDatagrama(miPuerto);
miSocket.connect(maquinaEmisora, puertoEmisor);
for(int i=0; i<10; i++)
System.out.println(miSocket.recibeMensaje());
miSocket.enviaMensaje(maquinaEmisora, puertoEmisor, mensaje);
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //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 basado


en la E/S en modo stream de los sistemas operativos Unix. Por definicin, un socket en modo
stream proporciona slo comunicaciones orientadas a conexin.
En modo stream, los datos se transfieren utilizando el concepto de un flujo de datos continuo
que fluye desde una fuente a un destino.
Usando el API, cada uno de los dos procesos crea individualmente un socket en modo stream.
A continuacin, se forma una conexin entre los sockets. Los datos se escriben, como un flujo de
caracteres, dentro del socket del emisor y, a continuacin, el receptor puede leerlos a travs de su
socket.
En Java, las clases ServerSocket y Socket proporcionan el API de sockets en modo stream. La
sintaxis del API est estrechamente vinculada con el paradigma cliente-servidor (Captulo 5).
29

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


La clase ServerSocket sirve para aceptar conexiones. Por claridad, se har referencia a ellos
como sockets de conexin.
La clase Socket proporciona el otro tipo de socket que permite intercambiar datos. Por claridad, se har referencia a ellos como sockets de datos.
Un proceso conocido como el servidor establece un socket de conexin y despus se queda a la
espera de las peticiones de conexin de otros procesos. Las peticiones se aceptan de una en una.
A travs 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 cliente
crea un socket, solicita una conexin con el servidor y, una vez aceptada, el socket del cliente se
conecta al socket de datos del servidor de manera que el cliente pueda pasar a leer y/o escribir
del flujo de datos.
Operaciones y sincronizacin de eventos
La clase ServerSocket permite el establecimiento de conexiones mientras que la clase Socket
sirve para la transferencia de datos. En las Tablas 4.4 y 4.5 se listan los mtodos principales y los
constructores de estas dos clases.
Tabla 4.4: Mtodos principales y constructores de la clase ServerSocket.

Mtodo/Constructor

Descripcin

ServerSocket(int puerto)

Crea un socket de servidor en un puerto especificado.

Socket accept() throws IOException

Espera que se solicite una conexin a este socket y la acepta. El


mtodo bloquea hasta que se haga una conexin.

void close() throws IOException

Cierra este socket.

void setSoTimeout(int plazo) throws


SocketException

Fija un plazo mximo de tiempo de espera (en ms), de manera


que una llamada accept() sobre este socket bloquee durante slo
esta cantidad de tiempo. Si el plazo expira, se activa una
java.io.InterruptedIOException.

Tabla 4.5: Mtodos principales y constructores de la clase Socket.

Mtodo/Constructor

Descripcin

Socket(InetAddress direccin, int puerto)

Crea un socket stream y lo conecta al nmero de puerto y la


direccin IP especificados.

void close() throws IOException

Cierra este socket.

InputStream getInputStream() throws IOException

Devuelve un flujo de entrada para que se puedan leer los datos


de este socket.

OutputStream getOutputStream() throws


IOException

Devuelve un flujo de salida para que se puedan escribir los datos


en este socket.

void setSoTimeout(int plazo) throws

Fija un plazo mximo de bloqueo de manera que una llamada

SocketException

read() en el InputStream asociado con este socket bloquee slo


durante esta cantidad de tiempo. Si el plazo de tiempo expira, se
activa una java.io.InterruptedIOException().

Respecto a la sincronizacin de eventos, las siguientes operaciones son bloqueantes:


Accept (aceptacin de una conexin). Si no hay ninguna peticin esperando, el proceso
servidor se suspender hasta que llegue una peticin de conexin.
La lectura de un flujo de entrada asociado a un socket de datos. Si la cantidad de datos
pedida no est actualmente presente en el flujo de datos, el proceso que solicita la lectura
se bloquear hasta que se haya escrito una cantidad de datos suficiente en el flujo de datos.
30

No se proporcionan mtodos read y write especficos, puesto que se deben utilizar los mtodos
asociados con las clases InputStream y OutputStream para realizar estas operaciones.
La Figura 17 muestra los flujos de ejecucin de un programa que espera una peticin de
conexin y de otro que solicita la conexin.

Figura 17: Flujos de ejecucin de un programa que espera una peticin de conexin y de otro que la solicita.

Ejemplo 4. Los Listados 11 y 12 ilustran la sintaxis bsica para los sockets en modo stream.
Ejemplo4AceptadorConexion acepta conexiones estableciendo un objeto ServerSocket en un puerto
especificado. Ejemplo4SolicitanteConexion crea un objeto Socket, especificando como argumentos el
nombre de la mquina y el nmero de puerto del aceptador. Una vez que el aceptador ha aceptado
la conexin, escribe un mensaje en el flujo de datos del socket. En el solicitante, el mensaje se lee
del flujo de datos y se visualiza.
Listado 11: Ejemplo4AceptadorConexion.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

import java.net.*;
import java.io.*;
/**
* Aplicacin que acepta una conexin y recibe un mensaje utilizando un socket
* en modo stream.
* Se esperan dos argumentos:
* <nmero de puerto del socket de servidor utilizado en este proceso>
* <mensaje, una cadena, para mandar>
*/
public class Ejemplo4AceptadorConexion {
public static void main(String[] args) {
if(args.length != 2)
System.out.println("Se requieren 2 argumentos");
else {
try {
int numPuerto = Integer.parseInt(args[0]);
String mensaje = args[1];
ServerSocket socketConexion = new ServerSocket(numPuerto);
System.out.println("Preparado para aceptar una conexin");
Socket socketDatos = socketConexion.accept();
System.out.println("Conexin aceptada");
OutputStream flujoSalida = socketDatos.getOutputStream();
PrintWriter salidaSocket = new PrintWriter(new OutputStreamWriter(
flujoSalida));
salidaSocket.println(mensaje);
salidaSocket.flush(); //Escribir los datos en el flujo del socket antes
de cerrarlo
System.out.println("Mensaje enviado");
socketDatos.close();
System.out.println("Socket de datos cerrado");
socketConexion.close();
System.out.println("Socket de conexin cerrado");

31

34
35
36
37
38
39
40

} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //fin class

Listado 12: Ejemplo4SolicitanteConexion.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

import java.net.*;
import java.io.*;
/**
* Aplicacin que solicita una conexin y manda un mensaje utilizando un socket
* en modo stream.
* Se esperan dos argumentos:
* <nombre de la mquina del aceptador de la conexin>
* <nmero de puerto del aceptador de la conexin>
*/
public class Ejemplo4SolicitanteConexion {
public static void main(String[] args) {
if(args.length != 2)
System.out.println("Se requieren 2 argumentos");
else {
try {
InetAddress maquinaAceptadora = InetAddress.getByName(args[0]);
int puertoAceptador = Integer.parseInt(args[1]);
Socket miSocket = new Socket(maquinaAceptadora, puertoAceptador);
System.out.println("Solicitud de conexin concedida");
InputStream flujoEntrada = miSocket.getInputStream();
BufferedReader socketInput = new BufferedReader(new InputStreamReader(
flujoEntrada));
System.out.println("Esperando leer");
String mensaje = socketInput.readLine();
System.out.println("Mensaje recibido");
System.out.println("\t" + mensaje);
miSocket.close();
System.out.println("Socket de datos cerrado");
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //fin class

Para permitir la separacin de la lgica de aplicacin y la lgica de servicio en los programas,


se emplea una subclase que esconde los detalles de los sockets de datos. El Listado 13 muestra el
cdigo de la clase MiSocketStream, que proporciona mtodos para leer y escribir de un socket de
datos.
Listado 13: MiSocketStream.java
1
2
3
4
5
6
7
8
9
10
11
12
13

import java.net.*;
import java.io.*;
/**
* Una clase de envoltura de Socket que contiene mtodos para mandar y
* recibir mensajes.
*/
public class MiSocketStream extends Socket {
private Socket socket;
private BufferedReader entrada;
private PrintWriter salida;
MiSocketStream(String maquinaAceptadora, int puertoAceptador) throws
SocketException, IOException {

32

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

socket = new Socket(maquinaAceptadora, puertoAceptador);


establecerFlujos();
}
MiSocketStream(Socket socket) {
this.socket = socket;
establecerFlujos();
}
private void establecerFlujos() {
InputStream flujoEntrada = socket.getInputStream();
entrada = new BufferedReader(new InputStreamReader(flujoEntrada));
OutputStream flujoSalida = socket.getOutputStream();
salida = new PrintWriter(new OutputStreamWriter(flujoSalida));
}
public void enviaMensaje(String mensaje) throws IOException {
salida.println(mensaje);
salida.flush();
}
public String recibeMensaje() throws IOException {
String mensaje = entrada.readLine();
return mensaje;
}
public void close() throws IOException {
socket.close();
}
} //fin class

Ejemplo 5. Los Listados 14 y 15 son revisiones del cdigo 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

import java.net.*;
import java.io.*;
/**
* Aplicacin que acepta una conexin y recibe un mensaje utilizando un socket
* en modo stream.
* Se esperan dos argumentos:
* <nmero de puerto del socket de servidor utilizado en este proceso>
* <mensaje, una cadena, para mandar>
*/
public class Ejemplo5AceptadorConexion {
public static void main(String[] args) {
if(args.length != 2)
System.out.println("Se requieren 2 argumentos");
else {
try {
int numPuerto = Integer.parseInt(args[0]);
String mensaje = args[1];
ServerSocket socketConexion = new ServerSocket(numPuerto);
System.out.println("Preparado para aceptar una conexin");
MiSocketStream socketDatos = new MiSocketStream(socketConexion.accept());
System.out.ptintln("Conexin aceptada");
socketDatos.enviaMensaje(mensaje);
System.out.println("Mensaje enviado");
socketDatos.close();
System.out.println("Socket de datos cerrado");
socketConexion.close();
System.out.println("Socket de conexin cerrado");
} //fin try
catch (Exception e) {
e.printStackTrace();
} // fin catch
} //fin else
} //fin main

33

38

} //fin class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.net.*;
import java.io.*;

Listado 15: Ejemplo5SolicitanteConexion.java

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

/**
* Aplicacin que solicita una conexin y manda un mensaje utilizando un socket
* en modo stream.
* Se esperan dos argumentos:
* <nombre de la mquina del aceptador de la conexin>
* <nmero de puerto del aceptador de la conexin>
*/
public class Ejemplo5SolicitanteConexion {
public static void main(String[] args) {
if(args.length != 2)
System.out.println("Se requieren 2 argumentos");
else {
try {
String maquinaAceptadora = args[0];
int puertoAceptador = Integer.parseInt(args[1]);
MiSocketStream miSocket = new MiSocketStream(maquinaAceptadora,
puertoAceptador);
System.out.println("Solicitud de conexin concedida");
String mensaje = miSocket.recibeMensaje();
System.out.println("Mensaje recibido:");
System.out.println("\t" + mensaje);
miSocket.close();
System.out.println("Socket de datos cerrado");
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin else
} //fin main
} //fin class

Utilizando la subclase MiSocketStream, es mucho ms cmodo realizar entrada y salida en el


socket.

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 (threads), de manera que un hilo de espera realiza una operacin de lectura bloqueante, mientras
que otro hilo permanece activo para procesar otras tareas. Sin embargo, la sobrecarga incurrida
puede ser perjudicial para el rendimiento.
Como alternativa, hay interfaces de programacin de sockets que proporcionan operaciones
de E/S no bloqueantes. A partir de la versin 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 programacin de sockets seguros son interfaces de sockets mejoradas con
medidas de seguridad de datos.
El nivel de sockets seguros
El nivel de sockets seguros (SSL, Secure Sockets Layer) fue un protocolo desarrollado para
transmitir documentos privados sobre Internet. Una API de SSL tiene mtodos o funciones similares al API de sockets, excepto en que los datos son cifrados antes de que se transmitan sobre
una conexin SSL.

34

La extensin de sockets seguros de Java


La extensin de sockets seguros de JAVA (JSSE) es un conjunto de paquetes de Java que
posibilita las comunicaciones seguras en Internet. Implementa una versin de los protocolos SSL
y TLS (Transport Layer Security) e incluye herramientas para el cifrado de datos, autentificacin
del servidor, integridad de mensajes y autentificacin de cliente opcional.
El API de JSSE se caracteriza por tener una sintaxis similar al API de sockets orientados a
conexin presentada en este captulo.

35

5.

El paradigma cliente-servidor

5.1.

Antecedentes

En la informtica distribuida, el paradigma cliente-servidor se refiere a un modelo de aplicaciones 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 cliente
acceden al servidor para obtener un servicio de red.
Los servicios de red (ftp, telnet, Daytime, etc.) son la aplicacin ms popular de la computacin
distribuida. Por servicio de red se entiende un servicio proporcionado para permitir a los usuarios
de la red compartir recursos.

5.2.

Cuestiones sobre el paradigma cliente-servidor

En la implementacin real del paradigma hay un nmero de cuestiones que se deben afrontar.
Una sesin de servicio
Se utilizar el trmino sesin para referirse a la interaccin entre el servidor y el cliente.
El servicio gestionado por un servidor puede ser accesible a mltiples clientes que quieran
utilizarlo, incluso concurrentemente. Cada cliente entabla una sesin separada e independiente
con el servidor, durante la cual el cliente conduce un dilogo con el servidor hasta haya obtenido
el servicio deseado.
El protocolo de un servicio
Se necesita un protocolo para especificar las reglas que deben observar el cliente y el servidor
durante una sesin de servicio. Especificaciones tales como (1) la manera de localizar el servicio,
(2) la secuencia de comunicacin entre los procesos, y (3) la representacin e interpretacin de
los datos intercambiados.
Localizacin del servicio
Debe existir un mecanismo que permita que un proceso cliente localice un servidor. En el esquema ms simple, la localizacin de un servicio es esttica y se puede identificar utilizando la
direccin del proceso servidor. Este es el esquema usado para los servicios de Internet, donde a
cada servicio de Internet se le asigna un nmero de puerto especfico.
En un nivel ms alto de abstraccin, un servicio puede identificarse utilizando un nombre
lgico registrado en un directorio o en un registro. El nombre lgico necesitar traducirse a la
ubicacin fsica del proceso servidor. Si la traduccin se realiza en tiempo de ejecucin, es posible
que la localizacin del servicio sea dinmica, en cuyo caso se dice que el servicio es transparente
de la ubicacin.
Comunicaciones entre procesos y sincronizacin de eventos
En el modelo cliente-servidor, la interaccin de los procesos sigue un patrn de peticinrespuesta, el cual se puede repetir indefinidamente hasta que concluya la sesin. Por cada peticin realizada, el cliente debe esperar por la respuesta del servidor antes de continuar.
El dilogo en cada sesin sigue un patrn descrito en el protocolo especificado por el servicio.
Cualquier implementacin del programa cliente o servidor debe adherirse a la especificacin del
protocolo. Entre otras cosas, la especificacin define (1) la secuencia de intercomunicaciones
entre el cliente y el servidor, (2) la sintaxis y la semntica de cada peticin y respuesta, y (3) la
accin esperada en cada lado al recibir una peticin o respuesta determinada.
Representacin de datos
La eleccin de la representacin de datos depende de la naturaleza y la necesidad del protocolo. Para un servicio sencillo como Daytime, es lgico utilizar una representacin en modo
texto.

36

Elegir una representacin de datos en modo texto para un protocolo tiene la ventaja de
permitir que el dilogo sea legible para todos, ya que se puede utilizar E/S en modo texto
estndar para mostrar los datos intercambiados.

5.3.

Ingeniera de software de un servicio de red

El conjunto de software que se necesita en la mquina cliente para proporcionar un servicio o aplicacin se denomina software del lado cliente, en contraposicin al software del lado
servidor, que incluye al programa servidor. Es posible desarrollar por separado e independientemente el software en ambos lados.
Se usar el protocolo Daytime como un ejemplo del proceso de desarrollo de un servicio de
red.
Arquitectura de software
La arquitectura de software de una aplicacin construida utilizando el modelo cliente-servidor
se puede describir de la siguiente manera:
Nivel de presentacin. 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 cliente
proporcione una interfaz de usuario mediante la cual un usuario en la mquina cliente
pueda solicitar el servicio y recibir la respuesta del servidor.
Nivel de lgica de aplicacin. En el lado del servidor, necesita obtenerse la hora del da del
sistema y mandarla a la mquina cliente. En el lado del cliente, hay que enviar al servidor
la peticin del usuario y mostrarle la respuesta del servidor.
Nivel de servicio. Los servicios requeridos para dar soporte a la aplicacin son (1) en el
lado del servidor, una lectura del reloj de la mquina servidora y (2) en ambos lados, un
mecanismo de IPC.
Las funcionalidades de los tres niveles deben estar presentes en el software conjunto.
Mecanismo de IPC
El mecanismo IPC seleccionado afectar a cmo las aplicaciones transmiten datos. Se presenta
la posibilidad de escoger entre (1) un socket datagrama sin conexin, (2) un socket datagrama
orientado a conexin, o (3) un socket en modo stream.
Los detalles del mecanismo se escondern completamente de la lgica de presentacin y
afectarn nicamente a la lgica de aplicacin.
Cliente-servidor Daytime usando sockets datagrama sin conexin
Software del lado cliente
Lgica de presentacin. El Listado 16 presenta la clase ClienteDaytime1.java, que encapsula la
lgica de presentacin del lado cliente. El cdigo en esta clase se ocupa meramente de obtener
la entrada del usuario y de mostrar la salida al mismo. Se realiza una llamada de mtodo a
una clase auxiliar, ClienteDaytimeAuxiliar1.java, el cual esconde los detalles de la lgica de la
aplicacin.
Lgica de aplicacin. La clase ClienteDaytimeAuxiliar1.java (Listado 17) encapsula la lgica
de aplicacin del lado cliente. Este mdulo realiza la IPC para mandar una peticin y recibir una
respuesta utilizando una subclase de DatagramSocket, MiSocketDatagramaCliente. A este mdulo
se le esconden los detalles de la utilizacin de sockets datagrama.
Lgica de servicio. La clase MiSocketDatagramaCliente.java (Listado 18) proporciona los detalles del servicio de IPC, en este caso utilizando el API de socket datagrama.
Listado 16: ClienteDaytime1.java
1
2
3

import java.io.*;
/**

37

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

* Lgica de presentacin de un ClienteDaytime.


*/
public class ClienteDaytime1 {
public static void main (String[] args) {
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try {
System.out.println("Bienvenido al cliente Daytime.\nCul es el nombre de la
mquina servidora?");
String nombreMaquina = br.readLine();
if(nombreMaquina.length() == 0)
nombreMaquina = "localhost";
System.out.println("Cul es el no de puerto de la mquina servidora?");
String numPuerto = br.readLine();
if(numPuerto.lentgth() == 0)
numPuerto = "13";
System.out.println("Marca de tiempo recibida del servidor" +
ClienteDaytimeAuxiliar1.obtenerMarcaTiempo(nombreMaquina, numPuerto));
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Listado 17: ClienteDaytimeAuxiliar1.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

import java.net.*;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

import java.io.*;
import java.net.*;

/**
* Mdulo que proporciona la lgica de aplicacin de un cliente de Daytime.
*/
public class ClienteDaytimeAuxiliar1 {
public static String obtenerMarcaTiempo(String nombreMaquina, String numPuerto) {
String marcaTiempo = "";
try {
InetAddress serverHost = InetAddress.getByName(nombreMaquina);
int serverPort = Integer.parseInt(numPuerto);
MiSocketDatagramaCliente miSocket = new MiSocketDatagramaCliente();
miSocket.enviaMensaje(serverHost, serverPort, "");
marcaTiempo = miSocket.recibeMensaje();
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
return marcaTiempo();
}
} //fin class

Listado 18: MiSocketDatagramaCliente.java

/**
* Subclase que contiene mtodos para mandar y recibir mensajes.
*/
public class MiSocketDatagramaCliente extends DatagramSocket {
static final int MAX_LON = 100;
MiSocketDatagramaCliente() throws SocketException {
super();
}
MiSocketDatagramaCliente(int numPuerto) throws SocketException {
super(numPuerto);
}
public void enviaMensaje(InetAddress maquinaReceptora, int puertoReceptor, String
mensaje) throws IOException {

38

byte[] almacenEnvio = mensaje.getBytes();


DatagramPacket datagrama = new DatagramPacket(almacenEnvio, almacenEnvio.length
, maquinaReceptora, puertoReceptor);
this.send(datagrama);

19
20
21
22
23
24
25
26
27
28
29
30
31
32

}
public String recibeMensaje() throws IOException {
byte[] almacenRecepcion = new byte[MAX_LON];
DatagramPacket datagrama = new DatagramPacket(almacenRecepcin, MAX_LON);
this.receive(datagrama);
String.mensaje = new String(almacenRecepcion);
return mensaje;
}
} //fin class

Software del lado servidor


Lgica de presentacin. Hay muy poca lgica de presentacin en el lado del servidor. En este 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 un
argumento en la lnea de comandos.
Lgica de aplicacin. La clase ServidorDaytime1.java (Listado 19) encapsula la lgica de aplicacin del lado servidor. Este mdulo ejecuta un bucle infinito, esperando una peticin de un
cliente y despus dirige una sesin de servicio para ese cliente. El mdulo realiza la IPC para
recibir una peticin y manda una respuesta utilizando una subclase de DatagramSocket, MiSocketDatagramaServidor.
Lgica de servicio. La clase MiSocketDatagramaServidor (Listado 20) proporciona los detalles
del servicio de IPC, en este caso utilizando el API de sockets datagrama. Esta clase devuelve un
objeto de la clase MensajeDatagrama (Listado 21) que contiene la direccin del emisor, as como
el mensaje en s mismo. El servidor necesita la direccin del emisor para mandar una peticin al
cliente. sta es una idiosincrasia del socket sin conexin: el servidor no tiene manera de conocer
dnde mandar una respuesta en caso contrario.
Listado 19: ServidorDaytime1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import java.io.*;
import java.util.Date;
/**
* Mdulo que contiene la lgica de aplicacin de un servidor Daytime que
* utiliza un socket datagrama para la comunicacin entre procesos.
* Se espera un argumento:
* <Puerto de escucha del servidor>
*/
public class ServidorDaytime1 {
public static void main (String[] args) {
int puertoServidor = 13; //por defecto
if(args.length == 1)
puertoServidor = Integer.parseInt(args[0]);
try {
MiSocketDatagramaServidor miSocket = new MiSocketDatagramaServidor(
puertoServidor);
System.out.println("Servidor Daytime preparado");
while (true) {
MensajeDatagrama peticion = miSocket.recibeMensajeYEmisor();
System.out.println("Peticin recibida");
Date marcaTiempo = new Date();
System.out.println("Marca de tiempo enviada: " + marcaTiempo.toString());
miSocket.enviaMensaje(peticion.obtieneDireccion(), peticion.obtienePuerto
(), marcaTiempo.toString());
} //fin while(true)
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

39

Listado 20: MiSocketDatagramaServidor.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

import java.net.*
import java.io.*;
/**
* Subclase de DatagramSocket que contiene mtodos para mandar y
* recibir mensajes.
*/
public class MiSocketDatagramaServidor extends DatagramSocket {
static final int MAX_LON = 100;
miSocketDatagramaServidor(int numPuerto) {
super(numPuerto);
}
public void enviaMensaje(InetAddress maquinaReceptora, int puertoReceptor, String
mensaje) throws IOException {
byte[] almacenEnvio = mensaje.getBytes();
DatagramPacket datagrama = new DatagramPacket(almacenEnvio, almacenEnvio.length
, maquinaReceptora, puertoReceptor);
this.send(datagrama)
}
public String recibeMensaje() throws IOException {
byte[] almacenRecepcion = new byte[MAX_LON];
DatagramPacket datagrama = new DatagramPacket(almacenRecepcion, MAX_LON);
this.receive(datagrama);
String mensaje = new String(almacenRecepcion);
return mensaje;
}
public MensajeDatagrama recibeMensajeYEmisor() throws IOException {
byte[] almacenRecepcion = new byte[MAX_LON];
DatagramPacket datagrama = new DatagramPacket(almacenRecepcion, MAX_LON);
this.receive(datagrama);
MensajeDatagrama valorDevuelto = new MensajeDatagrama();
valorDevuelto.fijaValor(new String(almacenRecepcion), datagrama.getAddress(),
datagrama.getPort());
return valorDevuelto;
}
} //fin class

Listado 21: MensajeDatagrama.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

import java.net.*;
/**
* Clase para utilizar con MiSocketDatagramaServidor para devolver
* un mensaje y la direccin del emisor.
*/
public class MensajeDatagrama {
private String mensaje;
private InetAddress direccionEmisor;
private int puertoEmisor;
public void fijarValor(String mensaje, InetAddress dir, int puerto) {
this.mensaje = mensaje;
this.direccionEmisor = dir;
this.puertoEmisor = puerto;
}
public String obtieneMensaje() {
return this.mensaje;
}
public InetAddress obtieneDireccion() {
return this.direccionEmisor;
}
public int obtienePuerto() {
return this.puertoEmisor;

40

28
29
30

}
} //fin class

Cliente-servidor Daytime usando sockets en modo stream


Supngase que se quiere implementar el mismo servicio utilizando en su lugar sockets orientados a conexin. Dado que este cambio slo afecta bsicamente a la lgica de servicio, slo
se necesitaran hacer modificaciones importantes en las clases de dicho nivel. La lgica de la
aplicacin, especficamente la clase auxiliar, se necesitar ajustar en consecuencia.
Software del lado cliente
Lgica de presentacin. El Listado 22 presenta la clase ClienteDaytime2, que es igual que ClienetDaytime1 excepto por un cambio en el nombre de la clase auxiliar, ClienteDaytimeAuxiliar2.
Lgica de aplicacin. La clase ClienteDaytimeAuxiliar2 (Listado 23), que encapsula la lgica
de aplicacin del lado cliente, es similar a la de la clase ClienteDaytimeAuxiliar1, excepto en que
se utiliza un socket en modo stream en lugar de un socket datagrama.
Lgica de servicio. La clase MiSocketStream (Listado 24) proporciona los detalles del servicio
de IPC, en este caso utilizando el API de sockets en modo stream.
Listado 22: ClienteDaytime2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

import java.io.*;
/**
* Lgica de presentacin de un ClienteDaytime.
*/
public class ClienteDaytime2 {
public static void main (String[] args) {
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try {
System.out.println("Bienvenido al cliente Daytime.\nCul es el nombre de la
mquina servidora?");
String nombreMaquina = br.readLine();
if(nombreMaquina.length() == 0)
nombreMaquina = "localhost";
System.out.println("Cul es el no de puerto de la mquina servidora?");
String numPuerto = br.readLine();
if(numPuerto.lentgth() == 0)
numPuerto = "13";
System.out.println("Marca de tiempo recibida del servidor" +
ClienteDaytimeAuxiliar2.obtenerMarcaTiempo(nombreMaquina, numPuerto));
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Listado 23: ClienteDaytimeAuxiliar2.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14

import java.net.*;
/**
* Mdulo que proporciona la lgica de aplicacin de un cliente de Daytime
* que utiliza un socket en modo stream para IPC.
*/
public class ClienteDaytimeAuxiliar2 {
public static String obtenerMarcaTiempo(String nombreMaquina, String numPuerto)
throws Exception {
String marcaTiempo = "";
int puertoServidor = Integer.parseInt(numPuerto);
System.out.println("Peticin de conexin realizada");
MiSocketStream miSocket = new MiSocketStream(nombreMaquina, puertoServidor);
marcaTiempo = miSocket.recibeMensaje();
miSocket.close();

41

15
16
17

return marcaTiempo();
}
} //fin class

1
2
3
4
5
6
7
8
9
10
11
12

import java.io.*;
import java.net.*;

Listado 24: MiSocketStream.java

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

/**
* Subclase que contiene mtodos para mandar y recibir mensajes
*/
public class MiSocketStream extends Socket {
private Socket socket;
private BufferedReader entrada;
private PrintWritter salida;
MiSocketStream(String maquinaAceptadora, int puertoAceptador) throws
SocketException, IOException {
socket = new Socket(maquinaAceptadora, puertoAceptador);
establecerFlujos();
}
MiSocketStream(Socket socket) throws IOException {
this.socket = socket;
establecerFlujos();
}
private void establecerFlujos() throws IOException {
InputStream flujoEntrada = socket.getInputStream();
entrada = new BufferedReader(new InputStreamReader(flujoEntrada));
OutputStream flujoSalida = socket.getOutputStream();
salida = new PrintWriter(new OutputStreamWriter(flujoSalida));
}
public void enviaMensaje(String mensaje) throws IOException {
salida.println(mensaje);
salida.flush();
}
public String recibeMensaje() throws IOException {
String mensaje = entrada.readLine();
return mensaje;
}
} //fin class

Software del lado servidor


Lgica de presentacin. El cdigo de ServidorDaytime2 (Listado 25) es idntico al de ServidorDaytime1.
Lgica de aplicacin. El cdigo de ServidorDaytime2 (Listado 25) usa el API de sockets en
modo stream para aceptar una conexin. La referencia de socket devuelta se utiliza despus para
instanciar un objeto MiSocketStream, cuyo mtodo enviaMensaje se emplea para transmitir una
marca de tiempo al cliente en el otro extremo de la conexin.
Lgica de servicio. La misma clase de envoltura utilizada en el cliente, MiSocketStream (Listado 24), se utiliza tambin en el servidor, ya que contiene los mtodos necesarios para la IPC en
modo stream.
Listado 25: ServidorDaytime2.java
1
2
3
4
5
6
7
8

import java.net.*;
import java.io.*;
import java.util.Date;
/**
* Mdulo que contiene la lgica de aplicacin de un servidor Daytime que
* utiliza un socket orientado a conexin para la comunicacin entre procesos.
* Se espera un argumento:

42

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

* <Puerto de escucha del servidor>


*/
public class ServidorDaytime2 {
public static void main (String[] args) {
int puertoServidor = 13; //por defecto
if(args.length == 1)
puertoServidor = Integer.parseInt(args[0]);
try {
ServerSocket miSocketConexion = new ServerSocket(puertoServidor);
System.out.println("Servidor Daytime preparado");
while (true) {
MiSocketStream miSocketDatos = new MiSocketStream(miSocketConexion.accept
());
System.out.println("Peticin recibida");
Date marcaTiempo = new Date();
System.out.println("Marca de tiempo enviada: " + marcaTiempo.toString());
miSocketDatos.enviaMensaje(marcaTiempo.toString());
miSocketDatos.close();
} //fin while(true)
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Prueba de un servicio de red


Es notoriamente difcil probar el buen funcionamiento del software de red. Algunos consejos
que pueden ser tiles son:
Utilice la arquitectura de tres niveles y organice en mdulos cada nivel tanto en el lado
cliente como en el lado servidor.
Use una estrategia gradual o paso a paso en el desarrollo de cada mdulo.
Desarrolle en primer lugar el cliente. A veces es til emplear un servidor de Echo, cuya
correccin sea ya conocida y que use un mecanismo IPC compatible, para probar el cliente
independientemente del servidor.
Utilice mensajes de diagnstico dentro del cdigo fuente.
Compruebe el conjunto cliente-servidor en una nica mquina antes de ejecutar los programas en mquinas separadas.

5.4.

Servidores orientados a conexin y sin conexin

El protocolo Echo permite a un cliente simplemente mandar lneas de texto a un servidor,


y recibir un eco de cada una de ellas. Puede usarse el servidor Echo por defecto de cualquier
mquina en Internet como un servidor sustituto temporal cuando un ingeniero de software est
desarrollando un cliente para otro protocolo.
Cliente-servidor Echo sin conexin
Los Listados 26, 27 y 28 presentan una implementacin del servicio Echo utilizando el API
de sockets datagrama sin conexin.
El cliente Echo La lgica de presentacin se encapsula en la clase ClienteEcho1. El envo de una
cadena de texto y la recepcin del eco devuelto se maneja mediante un mtodo, obtenerEco, de la
clase ClienteEchoAuxiliar1. La clase ClienteEchoAuxiliar1 proporciona la lgica de aplicacin del
cliente. Se crea una instancia de esta clase por cada proceso cliente.

43

El servidor Echo ServidorEcho1.java combina la lgica de presentacin y la lgica de aplicacin


para el servidor. En cada iteracin de un bucle infinito, el servidor lee una lnea del socket y
despus escribe la lnea de vuelta al socket, dirigiendo la respuesta al emisor. Es posible que
el servidor interaccione con diferentes clientes en iteraciones sucesivas, resultando sesiones de
servicio concurrentes intercaladas.
Listado 26: ClienteEcho1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

import java.io.*;
/**
* Mdulo que contiene la lgica de aplicacin de un cliente Echo.
*/
public class ClienteEcho1 {
static final String mensajeFin = ".";
public static void main (String[] args) {
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try {
System.out.println("Bienvenido al cliente Echo.\nCul es el nombre de la
mquina servidora?");
String nombreMaquina = br.readLine();
if(nombreMaquina.length == 0)
nombreMaquina = "localhost";
System.out.println("Introduzca el no de puerto de la mquina servidora");
String numPuerto = br.readLine();
if(numPuerto.length == 0)
numPuerto = "7";
ClienteEchoAuxiliar1 auxiliar = new ClienteEchoAuxiliar1(nombreMaquina,
numPuerto);
boolean hecho = false;
String mensaje, eco;
while(!hecho) {
System.out.println("Escriba una lnea para recibir el eco, o un nico
punto \".\" para terminar");
mensaje = br.readLine();
if((mensaje.trim()).equals(mensajeFin)) {
hecho = true;
auxiliar.hecho();
} else {
eco = auxiliar.obtenerEco(mensaje);
System.out.println(eco);
}
} //fin while
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Listado 27: ClienteEchoAuxiliar1.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

import java.net.*;
import java.io.*;
/**
* Mdulo que proporciona la lgica de applicacin para un cliente Echo
* utilizando un socket datagrama sin conexin.
*/
public class ClienteEchoAuxiliar1 {
private MiSocketDatagramaCliente miSocket;
private InetAddress maquinaServidora;
private int puertoServidor;
ClienteEchoAuxiliar1(String nombreMaquina, String numPuerto) throws
SocketException, UnknownHostException {
this.maquinaServidora = InetAddress.getByName(nombreMaquina);
this.puertoServidor = Integer.parseInt(numPuerto);

44

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

this.miSocket = new MiSocketDatagramaCliente();


}
public String obtenerEco(String mensaje) throws SocketException, IOException {
String eco = "";
miSocket.enviaMensaje(maquinaServidora, puertoServidor, mensaje);
eco = miSocket.recibeMensaje();
return eco;
}
public void hecho() throws SocketException {
miSocket.close();
}
} //fin class

Listado 28: ServidorEcho1.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import java.io.*;
/**
* Mdulo que contiene la lgica de aplicacin de un servidor Echo que utiliza un
socket
* datagrama sin conexin para la IPC.
* Requiere un argumento:
* <nmero de puerto del servidor>
*/
public class ServidorEcho1 {
public static void main (String[] args) {
int puertoServidor = 7;
if (args.length == 1)
puertoServidor = Integer.parseInt(args[0]);
try {
MiSocketDatagramaServidor miSocket = new MiSocketDatagramaServidor(
puertoServidor);
System.out.println("Servidor Echo preparado");
while(true) {
MensajeDatagrama peticion = miSocket.recibeMensajeYEmisor();
System.out.println("Peticin recibida");
String mensaje = peticion.obtieneMensaje();
System.out.println("Mensaje recibido: " + mensaje);
// Enviar el echo
miSocket.enviaMensaje(peticion.obtieneDireccion(), peticion.obtienePuerto
(), mensaje);
} //fine while(true)
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Cliente-servidor Echo orientado a conexin


Los Listados 29, 30 y 31 presentan una implementacin de un cliente y un servidor del servicio Echo utilizando el API de sockets en modo stream. La implementacin de la lgica de presentacin (en ClienteEcho2 y ServidorEcho2) es igual que *Echo1. Sin embargo, la lgica de aplicacin
(en ClienteEchoAuxiliar2 y ServidorEcho2), as como la lgica de servicio (en MiSocketStream) son
diferentes.
Listado 29: ClienteEcho2.java
1
2
3
4
5
6
7

import java.io.*;
/**
* Mdulo que contiene la lgica de aplicacin de un cliente Echo.
*/
public class ClienteEcho2 {
static final String mensajeFin = ".";

45

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

public static void main (String[] args) {


InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try {
System.out.println("Bienvenido al cliente Echo.\nCul es el nombre de la
mquina servidora?");
String nombreMaquina = br.readLine();
if(nombreMaquina.length == 0)
nombreMaquina = "localhost";
System.out.println("Introduzca el no de puerto de la mquina servidora");
String numPuerto = br.readLine();
if(numPuerto.length == 0)
numPuerto = "7";
ClienteEchoAuxiliar2 auxiliar = new ClienteEchoAuxiliar2(nombreMaquina,
numPuerto);
boolean hecho = false;
String mensaje, eco;
while(!hecho) {
System.out.println("Escriba una lnea para recibir el eco, o un nico
punto \".\" para terminar");
mensaje = br.readLine();
if((mensaje.trim()).equals(mensajeFin)) {
hecho = true;
auxiliar.hecho();
} else {
eco = auxiliar.obtenerEco(mensaje);
System.out.println(eco);
}
} //fin while
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Listado 30: ClienteEchoAuxiliar2.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

import java.net.*;
import java.io.*;
/**
* Mdulo que proporciona la lgica de applicacin para un cliente Echo
* utilizando un socket en modo stream.
*/
public class ClienteEchoAuxiliar2 {
static final String mensajeFin = ".";
private MiSocketStream miSocket;
private InetAddress maquinaServidora;
private int puertoServidor;
ClienteEchoAuxiliar2(String nombreMaquina, String numPuerto) throws
SocketException, UnknownHostException {
this.maquinaServidora = InetAddress.getByName(nombreMaquina);
this.puertoServidor = Integer.parseInt(numPuerto);
this.miSocket = new MiSocketStream(nombreMaquina, this.puertoServidor);
System.out.println("Peticin de conexin hecha");
}
public String obtenerEco(String mensaje) throws SocketException, IOException {
String eco = "";
miSocket.enviaMensaje(mensaje);
eco = miSocket.recibeMensaje();
return eco;
}
public void hecho() throws SocketException, IOException {
miSocket.enviaMensaje(mensajeFin);
miSocket.close();
}

46

32
33

} //fin class

Listado 31: ServidorEcho2.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

import java.io.*;
import java.net.*;
/**
* Mdulo que contiene la lgica de aplicacin de un servidor Echo que utiliza un
* socket en modo stream para la IPC.
* Requiere un argumento:
* <nmero de puerto del servidor>
*/
public class ServidorEcho2 {
static final String mensajeFin = ".";
public static void main (String[] args) {
int puertoServidor = 7;
String mensaje;
if (args.length == 1)
puertoServidor = Integer.parseInt(args[0]);
try {
ServerSocket miSocketConexion = new ServerSocket(puertoServidor);
System.out.println("Servidor Echo preparado");
while(true) {
System.out.println("Espera una conexin");
MiSocketStream miSocketDatos = new MiSocketStream(miSocketConexion.accept
());
System.out.println("Conexion aceptada");
boolean hecho = false;
while(!hecho) {
mensaje = miSocketDatos.recibeMensaje();
System.out.println("Mensaje recibido: " + mensaje);
if((mensaje.trim()).equals(mensajeFin)) {
System.out.println("Final de la sesin");
miSocketDatos.close();
hecho = true;
} else {
miSocketDatos.enviaMensaje(mensaje);
}
} //fin while(!hecho)
} //fin while(true)
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

5.5.

Servidor iterativo y servidor concurrente

Con un servidor orientado a conexin como ServidorDaytime2 y ServidorEcho2, no hay solapamiento de sesiones de cliente, ya que el servidor se limita a intercambiar datos con un cliente
cuya conexin ha aceptado. A este tipo de servidor se le denomina servidor iterativo, ya que
sirve a un cliente cada vez. Cuando se solicita un servicio a un servidor iterativo, un cliente se
bloquear hasta que se sirvan todos los clientes precedentes.
La solucin a este problema es introducir concurrencia en el servidor, dando lugar a un
servidor concurrente, que es capaz de gestionar mltiples sesiones de cliente en paralelo. Un
servidor concurrente se puede implementar con hilos o con operaciones de IPC asncronas.
Un servidor concurrente utiliza un nico socket de conexin para escuchar las conexiones.
Sin embargo, se crea un nuevo hilo para aceptar cada conexin y dirigir una sesin de servicio
con el cliente conectado; de manera que el hilo termina cuando concluye la sesin.
Los Listados 32 y 33 presentan el servidor concurrente y la clase que define el hilo que
utiliza, respectivamente. Ntese que no se necesita ningn cambio en el cdigo del lado del
47

cliente: puede utilizarse ClienteEcho2 para acceder a ServidorEcho3 sin ningn cambio.
Listado 32: ServidorEcho3.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import java.io.*;
import java.net.*;
/**
* Mdulo que contiene la lgica de aplicacin de un servidor Echo que utiliza un
* socket en modo stream para la IPC. Los clientes se sirven concurrentemente.
* Requiere un argumento:
* <nmero de puerto del servidor>
*/
public class ServidorEcho3 {
public static void main (String[] args) {
int puertoServidor = 7;
String mensaje;
if (args.length == 1)
puertoServidor = Integer.parseInt(args[0]);
try {
ServerSocket miSocketConexion = new ServerSocket(puertoServidor);
System.out.println("Servidor Echo preparado");
while(true) {
System.out.println("Espera una conexin");
MiSocketStream miSocketDatos = new MiSocketStream(miSocketConexion.accept
());
System.out.println("Conexion aceptada");
Thread elHilo = new Thread(new HiloServidorEcho(miSocketDatos));
elHilo.start(); //y continua con el siguiente cliente!
} //fin while(true)
} //fin try
catch (Exception e) {
e.printStackTrace();
} //fin catch
} //fin main
} //fin class

Listado 33: HiloServidorEcho.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import java.io.*;
/**
* Mdulo diseado para usarse con un servidor Echo concurrente.
* El mtodo run() lleva a cabo la lgica de una sesin de cliente.
*/
public class HiloServidorEcho implements Runnable {
static final String mensajeFin = ".";
MiSocketStream miSocketDatos;
HiloServidorEcho(MiSocketStream miSocketDatos) {
this.miSocketDatos = miSocketDatos;
}
public void run() {
boolean hecho = false;
String mensaje;
try {
while(!hecho) {
mensaje = miSocketDatos.recibeMensaje();
System.out.println("Mensaje recibido: " + mensaje);
if((mensaje.trim()).equals(mensajeFin)) {
System.out.println("Final de la sesin");
miSocketDatos.close();
hecho = true;
} else {
miSocketDatos.enviaMensaje(mensaje);
}
} //fin while(!hecho)
} //fin try
catch (Exception e) {
e.printStackTrace();

48

33
34
35
36

}
}
} //fin class

5.6.

Servidores con estado

Tanto el protocolo Daytime como el Echo pertenecen a una categora de protocolos conocida
como protocolos sin estado, en contraste con los protocolos con estado. Un protocolo es sin
estado cuando no necesita mantener ninguna informacin de estado en el servidor.
Un servidor con estado es uno que debe mantener alguna informacin de estado para proporcionar su servicio. Qu significa informacin de estado? Hay dos tipos: informacin de estado
global e informacin de estado de sesin.
Informacin de estado global
El servidor mantiene este tipo de informacin para todos los clientes durante la vida del
servidor. Supngase un protocolo, contador, que requiere que un servidor mantenga un contador
iniciado a 0. Cada vez que un cliente contacta con el servidor, ste incrementa el contador en 1 y
enva su valor actual al cliente. El Listado 34 muestra el cdigo de un servidor que implementa
el protocolo contador. Los Listados 45 y 36 muestran el programa cliente.
Listado 34: ServidorContador1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

import java.io.*;
/**
* Mdulo que contiene la lgica de aplicacin de un servidor Contador
* que utiliza un socket datagrama para la IPC.
* Requiere un argumento:
* <nmero de puerto del servidor>
* /
public class ServidorContador1 {
static int contador = 0;
public static void main (String[] args) {
int puertoServidor = 12345;
if(args.length == 1)
puertoServidor = Integer.parseInt(args[0]);
try {
MiSocketDatagramaServidor miSocket = new MiSocketDatagramaServidor(
puertoServidor);
System.out.println("Servidor contador preparado");
while(true) {
MensajeDatagrama peticion = miSocket.recibeMensajeYEmisor();
System.out.println("Peticin recibida");
incremento();
System.out.println("Contador enviado " + contador);
miSocket.enviaMensaje(peticion.obtieneDireccion(), peticion.obtienePuerto
(), String.valueOf(contador));
} //fin while(true)
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
static private synchronized void incremento() {
contador++;
}
} //fin class

Listado 35: ClienteContador1.java


1
2

import java.io.*;

49

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/**
* Mdulo que contiene la lgica de presentacin de un cliente Contador.
*/
public class ClienteContador 1 {
public static void main (String[] args) {
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try {
System.out.println("Bienvenido al cliente Contador.\nCul es el nombre de
la mquina servidora?");
String nombreMaquina = br.readLine();
if(nombreMaquina.length() == 0)
nombreMaquina = "localhost";
System.out.println("Cul es el nmero de puerto de la mquina servidora?");
String numPuerto = br.readLine();
if(numPuerto.length() == 0)
numPuerto = "12345";
System.out.println("Contador recibido del servidor: " +
ClienteContadorAuxiliar1.obtenerContador(nombreMaqina, numPuerto));
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
} //fin class

Listado 36: ClienteContadorAuxiliar1.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

import java.net.*;
/**
* Mdulo que proporciona la lgica de aplicacin para un cliente Contador.
*/
public class ClienteContadorAuxiliar1 {
public static int obtenerContador(String nombreMaquina, String numPuerto) {
int contador = 0;
String mensaje = "";
try {
InetAddress maquinaServidora = InetAddress.getByName(nombreMaquina);
int puertoServidor = Integer.parseInt(numPuerto);
MiSocketDatagramaCliente miSocket = new MiSocketDatagramaCliente();
miSocket.enviaMensaje(maquinaServidora, puertoServidor, "");
mensaje = miSocket.recibeMensaje();
System.out.println("Mensaje recibido: " + mensaje);
contador = Integer.parseInt(mensaje.trim());
miSocket.close();
} //fin try
catch (Exception e) {
e.printStackTrace();
}
return contador;
}
} //fin class

Informacin de estado de sesin


Algunos protocolos o aplicaciones tienen la necesidad de mantener informacin especfica
para una sesin de cliente.
Considrese un servicio de red tal como ftp. Un fichero es tpicamente transformado en
bloques, requirindose varias rondas de intercambios de datos para completar la transferencia
del fichero. La informacin de estado de cada sesin incluye:
1. El nombre del fichero con el que se est trabajando.
2. El nmero del bloque actual.
3. La accin (traer, llevar, etc.) que se est realizando sobre el fichero.
Hay al menos dos esquemas para mantener los datos de estado de sesin.
50

Servidor sin estado En este esquema, el cliente puede mantener la informacin de estado de
sesin de manera que cada peticin contenga la informacin de estado de sesin, permitiendo
al servidor procesar cada peticin de acuerdo con los datos de estado enviados en la peticin.
Servidor con estado En el segundo esquema, el servidor debe mantener la informacin del
estado de la sesin. El servidor controla el progreso de la sesin manteniendo el estado de la
misma.
En los servidores con estado, adems de la lgica requerida para mantener los datos del
estado, se debe prever la necesidad de salvaguardar la informacin de estado en el caso de que
se interrumpa una sesin.
Otro ejemplo de protocolo con estado corresponde con una aplicacin del tipo cesta de
la compra. Cada sesin debe mantener los datos de estado que hacen el seguimiento de la
identidad del comprador y de los contenidos acumulados en su cesta de compras.

51

7.
7.1.

Objetos distribuidos
Paso de mensajes frente a objetos distribuidos

El paradigma de paso de mensajes es apropiado para los servicios de red, puesto que estos
procesos interactan a travs del intercambio de mensajes. Pero no proporciona la abstraccin
necesaria para algunas aplicaciones de red complejas, por los siguientes motivos:
El paso de mensaje bsico requiere que los procesos participantes estn fuertemente acoplados. Los procesos deben comunicarse directamente entre ellos. Considrese una sesin
del protocolo Echo: si la comunicacin entre el cliente y el servidor es interrumpida, la
sesin no puede continuar.
El paradigma de paso de mensajes est orientado a datos. Cada mensaje contiene datos
con un formato mutuamente acordado, y se interpreta como una peticin o respuesta de
acuerdo al protocolo.
El hecho de que el paradigma sea orientado a datos no es adecuado para aplicaciones
complejas que impliquen un gran nmero de peticiones y respuestas entremezcladas.
El paradigma de objetos distribuidos proporciona mayor abstraccin. Este paradigma est basado en objetos existentes en un sistema distribuido. En programacin orientada a objetos, stos
se 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 mtodos pueden invocarse por un proceso remoto, es decir,
un proceso que se ejecuta en un computador conectado a travs de una red al computador en el
cual se encuentra el objeto. Los recursos de la red se representan como objetos distribuidos. Para
solicitar un servicio de un recurso de red, un proceso invoca uno de sus mtodos u operaciones,
pasndole los datos como parmetros al mtodo. El mtodo se ejecuta en la mquina remota, y
la respuesta es enviada al proceso solicitante como un valor de salida.

7.2.

Una arquitectura tpica de objetos distribuidos

La premisa de todo sistema de objetos distribuidos es minimizar las diferencias de programacin entre las invocaciones de mtodos remotos y las llamadas a mtodos locales. Deben tratarse
aspectos tales como el empaquetamiento de los datos (marshaling), as como la sincronizacin de
los eventos. Estas diferencias quedan ocultas en la arquitectura.
La Figura 18 presenta una arquitectura tpica de una utilidad que d soporte al paradigma
de objetos distribuidos.

Figura 18: Un sistema de objetos distribuidos tpico.

52

Al objeto distribuido proporcionado o exportado por un proceso se le denomina servidor de


objeto. Otra utilidad, denominada registro de objetos, o simplemente registro, debe existir en
la arquitectura para registrar los objetos distribuidos.
Para acceder a un objeto distribuido, un proceso, el cliente de objeto, busca en el registro
para encontrar una referencia al objeto. El cliente de objeto utiliza esta referencia para realizar llamadas a los mtodos del objeto remoto, o mtodos remotos. Un componente software
se encarga de gestionar esta llamada, denominado proxy de cliente, y se encarga tambin de
interactuar con el software en la mquina cliente con el fin de proporcionar soporte en tiempo
de ejecucin para el sistema de objetos distribuidos.
Una arquitectura similar es necesaria en la parte del servidor, donde el soporte en tiempo
de ejecucin para el sistema de objetos distribuidos gestiona la recepcin de los mensajes y el
desempaquetado de datos, enviando la llamada a un componente software denominado proxy
de servidor. El proxy de servidor invoca la llamada al mtodo local en el objeto distribuido,
pasndole los datos desempaquetados como argumentos. El resultado de la ejecucin del mtodo
es empaquetado y enviado por el proxy de servidor al proxy de cliente.

7.3.

Sistemas de objetos distribuidos

Entre las herramientas ms 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 para
aprender los detalles de utilidades similares.

7.4.

Llamadas a procedimientos remotos

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


RPC.
La programacin procedimental precede a la programacin orientada a objetos. La llamada
a un procedimiento convencional (no remoto) es una llamada a un procedimiento que reside en
el mismo sistema que el que la invoca y por tanto, se denomina llamada a procedimiento local.
Basndose en el modelo RPC, han aparecido un gran nmero de interfaces de programacin
de aplicaciones. Para enmascarar los detalles de la comunicacin entre procesos, cada llamada a
procedimiento remoto se transforma mediante una herramienta denominada rpcgen en una llamada a procedimiento local dirigida a un mdulo software comnmente denominado resguardo
(stub) o, ms formalmente, proxy. Los mensajes que representan la llamada al procedimiento y
sus argumentos se pasan a la mquina remota a travs del proxy.
Hay que destacar que hay que emplear un proxy a cada lado de la comunicacin para proporcionar el soporte en tiempo de ejecucin necesario para la comunicacin entre procesos,
llevndose a cabo el correspondiente empaquetado y desempaquetado de datos, as como las
llamadas a sockets necesarias.

7.5.

RMI (Remote Method Invocation)

RMI es una implementacin orientada a objetos del modelo de llamada a procedimientos


remotos. Se trata de una API exclusiva de Java.
En RMI, un servidor de objeto exporta un objeto remoto y lo registra en un servicio de
directorios. El objeto proporciona mtodos remotos, que pueden invocar los programas clientes.
Un objeto remoto se declara como una interfaz remota, una extensin de la interfaz Java. El
servidor de objeto implementa la interfaz remota. Un cliente de objeto accede al objeto mediante
la invocacin de sus mtodos, utilizando una sintaxis similar a las invocaciones de los mtodos
locales.

53

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, RMI
utiliza mdulos de software proxy para dar el soporte en tiempo de ejecucin necesario para
transformar la invocacin del mtodo remoto en una llamada a un mtodo local y gestionar
los detalles de la comunicacin entre procesos subyacente. Cada uno de los extremos de la
arquitectura est formado por tres capas de abstraccin, que veremos a continuacin.

Figura 19: La arquitectura de Java RMI.

Parte cliente de la arquitectura


1. La capa resguardo o stub. La invocacin de un mtodo remoto por parte de un proceso
cliente es dirigida a un objeto proxy, conocido como resguardo, Esta capa se encuentra
debajo de la capa de aplicacin y sirve para interceptar las invocaciones de los mtodos
remotos hechas por los programas clientes; una vez interceptada la invocacin es enviada
a la capa de referencia remota.
2. La capa de referencia remota interpreta y gestiona las referencias a los objetos de servicio
remoto 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 conexin. Esta capa
y el resto de la arquitectura se encargan de la conexin entre procesos, transmitiendo los
datos que representan la llamada al mtodo a la mquina remota.
Parte servidora de la arquitectura
1. La capa esqueleto o skeleton se encuentra justo debajo de la capa de aplicacin y se utiliza
para interactuar con la capa resguardo en la parte cliente.
2. La capa de referencia remota. Esta capa gestiona y transforma la referencia remota originada 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 transporte
orientada a conexin, es decir, TCP.
Registro de los objetos
El API de RMI hace posible el uso de diferentes servicios de directorios para registrar un
objeto distribuido. Uno de estos servicios de directorios es la interfaz de nombrado y directorios
de Java (JNDI). El registro RMI, rmiregistry, es un servicio de directorios sencillo proporcionado
por el kit de desarrollo de software Java (SDK). El registro RMI es un servicio cuyo servidor,

54

cuando est activo, se ejecuta en la mquina del servidor del objeto. Por convencin, utiliza el
puerto TCP 1099 por defecto.
Fsicamente, las invocaciones del mtodo remoto se transforman en llamadas a los resguardos
y esqueletos en tiempo de ejecucin, dando lugar a la transmisin de datos a travs de la red. La
Figura 20 es un diagrama de tiempos y eventos que describe la interaccin entre el resguardo y
el esqueleto.

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

7.7.

API de Java RMI

Esta seccin cubre las siguientes reas del API de Java RMI: la interfaz remota, el software
de 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 interfaz
remota es una interfaz que hereda de la clase Java remote, que permite implementar la interfaz
utilizando sintaxis RMI. Aparte de la extensin que se hace de la clase remote y de que todas
las declaraciones de los mtodos deben especificar la excepcin RemoteException, una interfaz
remota utiliza la misma sintaxis que una interfaz Java local. El Listado 37 muestra un ejemplo
de interfaz remota.
Listado 37: Un ejemplo de interfaz remota Java.
1
2
3
4
5
6
7
8

import java.rmi.*;
public interface InterfazEjemplo extends Remote {
public String metodoEj1() throws java.rmi.RemoteException;
public int metodoEj2(float parametro) throws java.rmi.RemoteException;
}

Obsrvese que un objeto serializable, tal como un objeto String o un objeto de otra clase, puede
ser un argumento o puede ser devuelto por un mtodo remoto. Al mtodo remoto se le pasa
una copia del elemento, sea ste un tipo primitivo o un objeto. El valor devuelto se gestiona de
la misma forma, pero en la direccin contraria.
55

Software de la parte servidora


Un servidor de objeto es un objeto que proporciona los mtodos y la interfaz de un objeto
distribuido. Cada servidor de objeto debe (1) implementar cada uno de los mtodos remotos
especificados en la interfaz, y (2) registrar en un servicio de directorios un objeto que contiene
la implementacin. Se recomienda que las dos partes se realicen en clases separadas.
La implementacin de la interfaz remota Se debe crear una clase que implemente la interfaz
remota. El Listado 38 muestra un esquema de la implementacin.
Listado 38: Sintaxis de un ejemplo de implementacin de interfaz remota.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.rmi.*;
import java.rmi.server.*;
/**
* Esta clase implementa InterfazEjemplo.
*/
public class ImplEjemplo extends UnicastRemoteObject implements InterfazEjemplo {
public ImplEjemplo() throws RemoteException {
super();
}
public String metodoEj1() throws RemoteException {
//Cdigo del mtodo
}
public int metodoEj2(float parametro) {
//Cdigo del mtodo
}
}

Generacin del resguardo y del esqueleto En RMI un objeto distribuido requiere un proxy
por cada uno de los servidores y clientes de objeto, conocidos como esqueleto y resguardo del
objeto, respectivamente. Estos proxies se generan a partir de la implementacin de una interfaz
remota utilizando una herramienta del SDK de Java: el compilador RMI rmic. Para utilizar esta
herramienta, se debe ejecutar el siguiente comando:
rmic ImplEjemplo
Si la compilacin se realiza con xito, se generan dos ficheros proxy, por ejemplo ImplEjemplo_skel.class y ImplEjemplo_stub.class. Estos ficheros son imprescindibles para que el programa
cliente pueda compilar correctamente. Una copia de cada fichero debe colocarse manualmente
en la parte cliente.
El servidor de objeto La clase del servidor de objeto instancia y exporta un objeto de la implementacin de la interfaz remota. El Listado 39 muestra una plantilla para la clase del servidor
de objeto.
Listado 39: Sintaxis de un ejemplo de un servidor de objeto.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

import
import
import
import
import
import

java.rmi.*;
java.rmi.server.*;
java.rmi.registry.Registry;
java.rmi.registry.LocateRegistry;
java.net.*;
java.io.*;

/**
* Clase que representa el servidor de un objeto distribuido de la clase
* ImplEjemplo, que implementa la interfaz remota InterfazEjemplo.
*/
public class ServidorEjemplo {
public static void main (String[] args) {

56

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

String numPuertoRMI, URLRegistro;


try {
ImplEjemplo objExportado = new ImplEjemplo();
arrancarRegistro(numPuertoRMI);
URLRegistro = "rmi://localhost:" + numPuerto + "/ejemplo";
Naming.rebind(URLRegistro, objExportado);
System.out.println("Servidor preparado");
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {
try {
Registry registro = LocateRegistry.getRegistry(numPuertoRMI);
registro.list(); //lanza excepcin si no existe
} //fin try
catch (Exception e) {
System.out.println("El registro RMI no se puede localizar en el puerto: " +
numPuertoRMI);
Registry registro = LocateRegistry.createRegistry(numPuertoRMI);
System.out.println("Registro RMI creado en el puerto: " + numPuertoRMI);
} //fin catch
} //fin arrancarRegistro
} //fin class

Analicemos las diferentes partes de esta plantilla.


Creacin de un objeto de la implementacin de la interfaz remota. En la lnea 17 se crea un
objeto de la clase que implementa la interfaz remota; a continuacin se exportar la referencia a
este objeto.
Exportacin del objeto. Las lneas 19-21 exportan el objeto. Se debe registrar su referencia
en un servicio de directorios. En este captulo utilizaremos el servicio rmiregistry, el cual debe
ejecutarse en el nodo del servidor de objeto para poder registrar objetos RMI.
En la plantilla del servidor de objeto, se implementa el mtodo esttico arrancarRegistro()
(lneas 28-38), que arranca un servidor de registro RMI si no est actualmente en ejecucin, en
un nmero de puerto especificado por el usuario.
En el cdigo para exportar un objeto (lneas 19-20), la clase Naming proporciona mtodos para
almacenar y obtener referencias del registro. En particular, el mtodo rebind permite almacenar
en el registro una referencia a un objeto con un URL de la forma:
rmi://<nombre mquina>:<nmero puerto>/<nombre referencia>
El mtodo rebind sobreescribe cualquier referencia en el registro asociada al nombre de la referencia. Si no se desea sobrescribir, existe un mtodo denominado bind.
Cuando se ejecuta un servidor de objeto, la exportacin de los objetos distribuidos provoca
que el proceso servidor comience a escuchar por el puerto y espere a que los clientes se conecten
y 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 localizar el registro RMI en el nodo servidor y buscar la referencia remota para el servidor de objeto;
a continuacin se realizar un cast de la referencia a la clase de la interfaz remota y se invocarn
los mtodos remotos. El Listado 40 presenta una plantilla para el cliente de objeto.
Listado 40: Plantilla para un cliente de objeto.
1
2
3
4
5
6
7
8

import
import
import
import

java.io.*;
java.rmi.*;
java.rmi.registry.Registry;
java.rmi.registry.LocateRegistry;

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

57

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

*/
public class ClienteEjemplo {
public static void main (String[] args) {
try {
int puertoRMI;
String nombreNodo;
String numPuerto;
String URLRegistro = "rmi://localhost:" + numPuerto + "/ejemplo";
InterfazEjemplo h = (InterfazEjemplo)Naming.lookup(URLRegistro);
String mensaje = h.metodoEj1();
System.out.println(mensaje);
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
} //fin class

7.8.

Una aplicacin RMI de ejemplo

En los Listados 41 a 44 se muestran los ficheros necesarios para crear la aplicacin RMI
HolaMundo. El servidor exporta un objeto que contiene un nico mtodo, denominado decirHola.
Listado 41: HolaMundoInt.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14

import java.rmi.*;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

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

/**
* Interfaz remota.
*/
public interface HolaMundoInt extends Remote {
/**
* Devuelve un mensaje.
* @param name - Una cadena de caracteres con un nombre
* @return - Una cadena de caracteres.
*/
public String decirHola(String nombre) throws java.rmi.RemoteException;
}

Listado 42: HolaMundoImpl.java

/**
* Implementacin de la interfaz remota.
*/
public class HolaMundoImpl extends UnicastRemoteObjetc implements HolaMundoInt {
public HolaMundoImpl() throws RemoteException {
super();
}
public String decirHola(String nombre) throws RemoteException {
return "Hola mundo! " + nombre;
}
}

Listado 43: HolaMundoServidor.java


1
2
3
4
5

import
import
import
import
import

java.io.*;
java.net.*;
java.rmi.*;
java.rmi.server.*;
java.rmi.registry.Registry;

58

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

import java.rmi.registry.LocateRegistry;
/**
* Clase que representa el servidor de un objeto de la clase HolaMundo,
* que implementa la interfaz remota HolaMundoInt.
*/
public class HolaMundoServidor {
public static void main (String[] args) {
InputStreamReader ent = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReader(ent);
String numPuerto, URLRegistro;
try {
System.out.println("Introducir el nmero de puerto del registro RMI:");
numPuerto = buf.readLine().trim();
int numPuertoRMI = Integer.parseInt(numPuerto);
arrancarRegistro(numPuertoRMI);
HolaMundoImpl objExportado = new HolaMundoImpl();
URLRegistro = "rmi://localhost:" + numPuerto + "/holaMundo";
Naming.rebind(URLRegistro, objExportado);
System.out.println("Servidor registrado. El registro contiene actualmente:")
;
listarRegistro(URLRegistro);
System.out.println("Servidor Hola Mundo preparado");
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
/**
* Arrancar un registro RMI en la mquina local, si es posible.
*/
private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {
try {
Registry registro = LocateRegistry.getRegistry(numPuertoRMI);
registro.list(); //lanza excepcin si no existe
} //fin try
catch (RemoteException e) {
System.out.println("El registro RMI no se localiza en el puerto " +
numPuertoRMI);
Registry registro = LocateRegistry.createRegistry(numPuertoRMI);
System.out.println("Registro RMI creado en el puerto " + numPuertoRMI);
} //fin catch
} //fin arrancarRegistro
/**
* Listar los nombres registrados con un objeto Registry
*/
private static void listarRegistro(String URLRegistro) throws RemoteException,
MalformedURLException {
System.out.println("Registro " + URLRegistro + " contiene: ");
String[] nombres = Naming.list(URLRegistro);
for (int i = 0; i<nombres.length; i++)
System.out.println(nombres[i]);
} //fin listaRegistro
} //fin class

Listado 44: HolaMundoCliente.java


1
2
3
4
5
6
7
8
9

import java.io.*;
import java.rmi.*;
/**
* Clase que representa el cliente de un objeto distribuido de clase HolaMundo,
* que implementa la interfaz remota HolaMundoInt.
*/
public class HolaMundoCliente {
public static void main (String[] args) {

59

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

try {
int numPuertoRMI;
String nombreNodo;
InputStreamReader ent = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReader(ent);
System.out.println("Introducir el nombre del nodo del registro RMI:");
nombreNodo = buf.readLine();
System.out.println("Inroducir el nmero de puerto del registro RMI:");
String numPuerto = buf.readLine();
numPuertoRMI = Integer.parseInt(numPuerto);
String URLRegistro = "rmi://" + nombreNodo + ":" + numPuerto + "/holaMundo";
//Buscar objeto remoto
HolaMundoInterfaz h = (HolaMundoInterfaz)Naming.lookup(URLRegistro);
System.out.println("Bsqueda completa");
//Invocar mtodo remoto
String mensaje = h.decirHola("Pato Donald");
System.out.println("HolaMundoCliente: " + mensaje);
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
} //fin class

7.9.

Pasos para construir una aplicacin RMI

Se va a describir paso a paso el procedimiento para construir una aplicacin RMI. Se describe
tanto la parte del servidor de objeto como del cliente de objeto. El algoritmo es expresado en
trminos de una aplicacin denominada Ejemplo.
Algoritmo para desarrollar el software de la parte servidora
1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicacin.
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 implementacin y generar
los ficheros de resguardo y esqueleto para el objeto remoto:
rmic ImplEjemplo
Los ficheros generados se encontrarn en el directorio como ImplEjemplo_Stub.class e ImplEjemplo_Skel.class. Se deben repetir los pasos 3 y 4 cada vez que se realice un cambio a la
implementacin 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 aplicacin.
2. Obtener una copia del fichero class (compilado) de la interfaz remota.
3. Obtener una copia del fichero de resguardo para la implementacin de la interfaz, ImplEjemplo_Stub.class.
4. Desarrollar el programa cliente ClienteEjemplo.java. Compilarlo y revisarlo.
5. Activar el cliente.
java ClienteEjemplo

60

7.10.

Pruebas y depuracin

Es recomendable utilizar los siguientes pasos incrementales a la hora de desarrollar una


aplicacin RMI:
1. Construir una plantilla para un programa RMI bsico. Empezar con una interfaz remota
que slo contenga la declaracin de un mtodo, su implementacin utilizando un resguardo, un programa servidor que exporte el objeto y un programa cliente con cdigo que slo
invoque al mtodo remoto.
2. Aadir una declaracin cada vez a la interfaz. Con cada adicin, modificar el programa
cliente para que invoque al mtodo que se ha aadido.
3. Rellenar la definicin de cada mtodo remoto uno a uno. Probar y depurar de forma
detallada cada mtodo antes de incluir el siguiente.
4. Despus de que todos los mtodos remotos se han probado detalladamente, crear la aplicacin cliente utilizando una tcnica incremental.
5. Distribuir los programas en mquinas separadas. Probarlos y depurarlos.

7.11.

Comparacin entre RMI y el API de sockets

El API de RMI es una herramienta eficiente para construir aplicaciones de red. Puede utilizarse en lugar del API de sockets para construir una aplicacin de red rpidamente. Adems de
ventajas, tambin existen desventajas en esta opcin:
1. El API de sockets est ms cercano al sistema operativo, por lo que tiene menos sobrecarga
de ejecucin. RMI requiere soporte software adicional (proxies y el servicio de directorio)
que implican una sobrecarga en tiempo de ejecucin.
2. El API de RMI proporciona la abstraccin necesaria para facilitar el desarrollo de software.
Los programas desarrollados en RMI son ms comprensibles y por tanto ms sencillos de
depurar.
3. El API de sockets se trata de una API tpicamente independiente de plataforma y lenguaje.
Java RMI requiere soportes de tiempo de ejecucin especficos de Java. Una aplicacin Java
RMI debe escribirse en Java y slo se puede ejecutar en plataformas Java.

61

8.

RMI avanzado

Este captulo analizar algunas de las caractersticas avanzadas de RMI ms interesantes, a


saber, descarga de resguardo, gestores de seguridad y callback de cliente. Se trata de mecanismos que pueden ser tiles para los desarrolladores de aplicaciones. El estudio de estos temas
permite reforzar el conocimiento del paradigma de objetos distribuidos en general.

8.1.

Callback de cliente

Considrese una aplicacin RMI donde un servidor de objeto debe notificar a los procesos
participantes la ocurrencia de algn evento. Dentro del entorno del API bsica de RMI presentada en el captulo anterior, es imposible que el servidor inicie una llamada al cliente para
transmitirle alguna clase de informacin, debido a que una llamada a mtodo remoto es unidireccional. Una forma de llevar a cabo la transmisin de informacin es que cada proceso cliente
realice un sondeo al servidor de objeto, invocando de forma repetida un mtodo remoto.
El sondeo (polling) se trata de una tcnica muy costosa en trminos de recursos del sistema.
Una tcnica ms eficiente se denomina callback: permite que cada cliente de objeto interesado
en la ocurrencia de un evento se registre a s mismo con el servidor de objeto, de forma que el
servidor inicie una invocacin de un mtodo remoto del cliente de objeto cuando dicho evento
ocurra.
En RMI, el callback de cliente es una caracterstica que permite a un cliente de objeto registrarse a s mismo con un servidor de objeto remoto para callbacks, de forma que el servidor
pueda llevar a cabo una invocacin del mtodo del cliente cuando el evento ocurra. Las invocaciones de los mtodos remotos se convierten en bidireccionales, o dplex. Se necesita claramente
sintaxis adicional para dar soporte a esta nueva caracterstica.
Cuando un servidor de objeto realiza un callback, los papeles de los dos procesos se invierten: el servidor de objeto se convierte en cliente del cliente de objeto. La Figura 21 muestra la
arquitectura de RMI con callback de cliente. Se puede observar que en este caso se necesitan dos
conjuntos de proxies. La interfaz remota del cliente proporciona un mtodo remoto que puede
invocar el servidor a travs del callback.

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

Como ejemplo, se extender la aplicacin HolaMundo de forma que el cliente del objeto se
registre con el servidor para callback y entonces se le notifique de cualquier registro de otro
cliente de objeto para callback con el servidor.

62

Extensin de la parte cliente para callback de cliente


Para el callback, el cliente debe proporcionar un mtodo remoto que permita al servidor
notificarle el evento correspondiente.
La interfaz remota de cliente
El servidor de objeto proporciona una interfaz remota que declara los mtodos que un cliente
de objeto puede invocar. Para el callback, es necesario que el cliente de objeto proporcione una
interfaz remota similar. Se le denominar interfaz remota de cliente (InterfazCallbackCliente). La
interfaz remota de cliente debe contener al menos un mtodo que ser invocado por el servidor
en 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 mtodo notificame cuando realiza el callback, pasando como argumento una cadena de caracteres. Una vez recibido el callback, el cliente compone otra cadena de
caracteres que devuelve al servidor.
La implementacin de la interfaz remota de cliente
Es necesario implementar la interfaz remota de cliente en una clase (ImplCallbackCliente), tal y
como se muestra a continuacin:
import java.rmi.*;
import java.rmi.server.*;
public class ImplCallbackCliente extends UnicastRemoteObject implements
InterfazCallbackCliente {
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 implementacin de la interfaz remota de cliente para generar los proxies necesarios en tiempo de
ejecucin.
Extensin de la clase cliente
Se necesita aadir cdigo al cliente para que instancie un objeto de la implementacin de la
interfaz remota de cliente. A continuacin, se registra con el servidor una referencia al objeto
utilizando un mtodo remoto proporcionado por el servidor. Un ejemplo de cmo debe realizarse esto es:
InterfazCallbackServidor h = (InterfazCallbackServidor)Naming.lookup(URLRegistro);
InterfazCallbackCliente objCallback = new InterfazCallbackCliente();
h.registrarCallback(objCallback);

Los listados 45 a 47 presentan el cdigo del software de la parte cliente para la aplicacin
HolaMundo modificada.
Listado 45: Fichero InterfazCallbackCliente.java de la aplicacin HolaMundo modificada.
1
2
3
4

import java.rmi.*;
/**
* Interfaz remota para ilustrar el callback de cliente.

63

5
6
7
8
9
10
11
12
13
14

*/
public interface InterfazCallbackCliente extends java.rmi.Remote {
/**
* @param mensaje - Cadena de caracteres que contiene informacin procesada por
* el cliente.
*/
public String notificame(String mensaje) throws java.rmi.RemoteException;
}

Listado 46: Fichero ImplCallbackCliente.java de la aplicacin HolaMundo modificada.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import java.rmi.*;
import java.rmi.server.*;
/**
* Clase que implementa la interfaz remota InterfazCallbackCliente.
*/
public class ImplCallbackCliente extends UnicastRemoteObject implements
InterfazCallbackCliente {
public ImplCallbackCliente() throws RemoteException {
super();
}
public String notificame(String mensaje) {
String mensajeRet = "Callback recibido: " + mensaje;
System.out.println(mensajeRet);
return mensajeRet;
}
}

Listado 47: Fichero ClienteEjemplo.java de la aplicacin HolaMundo modificada.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

import java.io.*;
import java.rmi.*;
/**
* Clase que representa el cliente de objeto para un objeto distribuido
* de la clase ImplCallbackServidor, que implementa la interfaz remota
* InterfazCallbackServidor. Tambin acepta callbacks del servidor.
*/
public class ClienteEjemplo {
public static void main(String[] args) {
try {
int puertoRMI;
String nombreNodo;
InputStreamReader ent = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReaedr(ent);
System.out.println("Introduce el nombre de nodo del registro RMI:");
nombreNodo = buf.readLine();
System.out.println("Introduce el nmero de puerto del registro RMI:");
String numPuerto = buf.readLine();
puertoRMI = Integer.parseInt(numPuerto);
System.out.println("Introduce cuntos segundos va a permanecer registrado:")
;
String duracionTiempo = buf.readLine();
int tiempo = Integer.parseInt(duracionTiempo);
String URLRegistro = "rmi://localhost:" + numPuerto + "/callback";
//Buscar objeto remoto y cast
InterfazCallbackServidor h = (InterfazCallbackServidor)Naming.lookup(
URLRegistro);
System.out.println("Bsqueda completa.");
System.out.println("El servidor dice " + h.decirHola());
InterfazCallbackCliente objCallback = new ImplCallbackCliente();
h.registrarCallback(objCallback);

64

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

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


try {
thread.sleep(tiempo*1000);
}
catch (InterruptedException e) {
h.eliminarRegistroCallback(objCallback);
System.out.println("No registrado para callback");
}
} //fin try
catch (Exception e) {
System.out.println("Excepcin en ClienteEjemplo: " + e);
}
} //fin main
} //fin class

Extensin de la parte servidora para callback de cliente


En la parte del servidor, se necesita aadir un mtodo remoto para que el cliente pueda
registrarse para callback. En el caso ms sencillo, la cabecera del mtodo puede ser anloga a:
public void registrarCallback (InterfazCallbackCliente objCallbackCliente) throws
java.rmi.RemoteException;

La implementacin de estos mtodos, as como la implementacin de un mtodo local hacerCallbacks se muestra en el Listado 49. El Listado 48 muestra el fichero con la interfaz del servidor.
El Listado 50 muestra el cdigo para el servidor de objeto, que queda sin modificar con respecto
a la anterior versin.
Listado 48: Fichero InterfazCallbackServidor.java de la aplicacin HolaMundo modificada.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

import java.rmi.*;
/**
* Interfaz remota para ilustrar el callback de cliente.
*/
public interface InterfazCallbackServidor extends Remote {
public String decirHola() throws java.rmi.RemoteException;
/**
* @param objClienteCallback - referencia al cliente de objeto; el servidor lo
utiliza para realizar los callbacks.
*
*/
public void registrarCallback(InterfazCallbackCliente objCallbackCliente) throws
java.rmi.RemoteException;

15
16
17
18

public void eliminarRegistroCallback(InterfazCallbackCliente objCallbackCliente)


throws java.rmi.RemoteException;
}

Listado 49: Fichero ImplCallbackServidor.java de la aplicacin HolaMundo modificada.


1
2
3
4
5
6
7
8
9
10
11
12
13
14

import java.rmi.*;
import java.rmi.server.*;
import java.util.Vector;
/**
* Clase que implementa la interfaz remota.
*/
public class ImplCallbackServidor extends UnicastRemoteObject implements
InterfazCallbackServidor {
private vector listaClientes;
public ImplCallbackServidor() throws RemoteException {
super();
listaClientes = new Vector();
}

65

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

public String decirHola() throws RemoteException {


return("Hola mundo");
}
public void registrarCallback(InterfazCallbackCliente objCallbackCliente) throws
RemoteException {
if(!(listaClientes.contains(objCallbackCliente))) {
listaClientes.addElement(objCallbackCliente);
System.out.println("Nuevo cliente registrado");
hacerCallbacks();
}
}
public synchronized void eliminarRegistroCallback(InterfazCallbackCliente
objCallbackCliente) throws RemoteException {
if(listaClientes.removeElement(objCallbackCliente)) {
System.out.println("Cliente no registrado");
} else {
System.out.println("eliminarRegistroCallback: el cliente no fue registrado")
;
}
}
private synchronized void hacerCallbacks() throws RemoteException {
System.out.println("*******************************************\nCallback
iniciado -- ");
for(int i = 0; i<listaClientes.size(); i++) {
System.out.println("Haciendo callback nmero " + i + "\n");
InterfazCallbackCliente proxCliente = (InterfazCallbackCliente)listaClientes
.elementAt(i);
proxCliente.notificame("Nmero de clientes registrados=" + listaClientes.
size());
}
System.out.println("*******************************************\nServidor
complet callbacks -- ");
}
} //fin class

Listado 50: Fichero ServidorEjemplo.java de la aplicacin HolaMundo modificada.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import
import
import
import
import
import

java.rmi.*;
java.rmi.server.*;
java.rmi.registry.Registry;
java.rmi.registry.LocateRegistry;
java.net.*;
java.io.*;

/**
* Clase que representa el servidor de un objeto distribuido de la clase
* Callback, que implementa la interfaz remota InterfazCallback.
*/
public class ServidorEjemplo {
public static void main (String[] args) {
InputStreamReader ent = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReader(ent);
String numPuerto, URLRegistro;
try {
System.out.println("Introducir el nmero de puerto del registro RMI:");
numPuerto = (buf.readLine()).trim();
int numPuertoRMI = Integer.parseInt(numPuerto);
arrancarRegistro(numPuertoRMI);
ImplCallbackServidor objExportado = new ImplCallbackServidor();
URLRegistro = "rmi://localhost:" + numPuerto + "/callback";
Naming.rebind(URLRegistro, objExportado);
System.out.println("Servidor callback preparado");
}
catch (Exception e) {
System.out.println("Excepcin en ServidorEjemplo.main: " + e);

66

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

}
} //fin main
private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {
try {
Registry registro = LocateRegistry.getRegistry(numPuertoRMI);
registro.list(); //lanza excepcin si no existe
}
catch (Exception e) {
System.out.println("El registro RMI no se puede localizar en el puerto: " +
numPuertoRMI);
Registry registro = LocateRegistry.createRegistry(numPuertoRMI);
System.out.println("Registro RMI creado en el puerto: " + numPuertoRMI);
}
} //fin arrancarRegistro
} //fin class

Pasos para construir una aplicacin 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 aplicacin.
2. Especificar la interfaz remota del servidor en InterfazCallbackServidor.java. Compilarla y ejecutarla.
3. Implementar la interfaz en ImplCallbackServidor.java. Compilarla y revisarla.
4. Utilizar el compilador RMI rmic para procesar la clase de la implmentacin y generar los
ficheros resguardo y esqueleto para el objeto remoto:
rmic ImplCallbackServidor
Los pasos 3 y 4 deben repetirse cada vez que se cambie la implementacin 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. Compilarlo
y revisarlo.
7. Obtener una copia del fichero resguardo de la interfaz de la interfaz remota del cliente
ImplCallbackCliente_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 aplicacin.
2. Especificar la interfaz remota de cliente en InterfazCallbackCliente.java. Compilarla y revisarla.
3. Implementar la interfaz en ImplCallbackCliente.java. Compilarla y revisarla.
4. Utilizar el compilador RMI rmic para procesar la clase de la implementacin ImplCallbackCliente.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 implementacin de la interfaz.
5. Obtener una copia del fichero class de la interfaz remota del servidor.

67

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


revisarlo.
7. Obtener una copia del fichero resguardo de la interfaz remota del servidor ImplCallbackServidor_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 dinmicamente
los resguardos necesarios. Mediante descarga dinmica de resguardo, no se necesita una copia
de la clase del resguardo en la mquina cliente. Por el contrario, ste se transmite bajo demanda
desde un servidor web a la mquina cliente cuando se activa dicho cliente.
Mediante el uso de descarga dinmica, el desarrollador almacena una clase resguardo en un
servidor web como un documento web, que puede ser descargado (utilizando HTTP) cuando
un 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 permanente en la mquina cliente, sino que por el contrario el sistema libera la clase correspondiente
cuando la sesin del cliente finaliza.

8.3.

El gestor de seguridad de RMI

La descarga de resguardo supone un problema para el sistema de seguridad. Cuando un


objeto como un resguardo RMI se transfiere desde un nodo remoto, su ejecucin entraa el
riesgo de ataques maliciosos al nodo local.
Java proporciona una clase denominada RMISecurityManager. Un programa RMI puede instanciar un objeto de esta clase. Una vez instanciado, el objeto supervisa durante la ejecucin
del programa todas las acciones que puedan suponer un riesgo de seguridad. En particular, el
soporte en tiempo real de RMI requiere que un proceso servidor instale un gestor de seguridad
antes de exportar cualquier objeto que requiera descarga de resguardo, y que un cliente instale
un gestor de seguridad antes de que pueda realizar la descarga del resguardo.
Aunque la nocin de gestor de seguridad no se introdujo en el captulo anterior, se recomienda su
uso 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 y
slo permite conexiones a la mquina origen. Es posible relajar estas condiciones instalando un
fichero especial conocido como fichero de poltica de seguridad, cuya sintaxis especifica el tipo
de restriccin que un gestor de seguridad debe utilizar. Alternativamente, una aplicacin puede
especificar un fichero de polticas de seguridad, de forma que las restricciones las impone la
propia aplicacin. Se recomienda que se especifique un fichero de seguridad con cada aplicacin
que se ejecute, de forma que se tenga control exclusivamente sobre las restricciones impuestas
en la aplicacin que se use, sin afectar a las restricciones de otros programas.
A continuacin, se describe cmo una aplicacin utiliza el gestor de seguridad de RMI.
Instanciacin de un gestor de seguridad en un programa RMI
La clase RMISecurityManager se puede instanciar tanto en el cliente de objeto como en el
servidor de objeto utilizando la siguiente sentencia:
System.setSecurityManager(new RMISecurityManager());
Esta sentencia debera aparecer antes del cdigo de acceso al registro RMI. Los Listados 51 y
52 muestran los ejemplo del programa HolaMundo, presentados en el captulo anterior, pero
instanciando un gestor de seguridad.
Listado 51: HolaMundoServidor.java haciendo uso de un gestor de seguridad.
1
2

import java.io.*;
import java.net.*;

68

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

import
import
import
import

java.rmi.*;
java.rmi.server.*;
java.rmi.registry.Registry;
java.rmi.registry.LocateRegistry;

/**
* Clase que representa el servidor de un objeto de la clase HolaMundo,
* que implementa la interfaz remota HolaMundoInt.
* Se instala un
*/
public class HolaMundoServidor {
public static void main (String[] args) {
InputStreamReader ent = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReader(ent);
String numPuerto, URLRegistro;
try {
System.out.println("Introducir el nmero de puerto del registro RMI:");
numPuerto = buf.readLine().trim();
int numPuertoRMI = Integer.parseInt(numPuerto);
// Arrancar un gestor de seguridad - necesario si se utiliza la
// descarga de resguardo
System.setSecurityManager(new RMISecurityManager());
arrancarRegistro(numPuertoRMI);
HolaMundoImpl objExportado = new HolaMundoImpl();
URLRegistro = "rmi://localhost:" + numPuerto + "/holaMundo";
Naming.rebind(URLRegistro, objExportado);
System.out.println("Servidor registrado. El registro contiene actualmente:")
;
listarRegistro(URLRegistro);
System.out.println("Servidor Hola Mundo preparado");
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
/**
* Arrancar un registro RMI en la mquina local, si es posible.
*/
private static void arrancarRegistro(int numPuertoRMI) throws RemoteException {
try {
Registry registro = LocateRegistry.getRegistry(numPuertoRMI);
registro.list(); //lanza excepcin si no existe
} //fin try
catch (RemoteException e) {
System.out.println("El registro RMI no se localiza en el puerto " +
numPuertoRMI);
Registry registro = LocateRegistry.createRegistry(numPuertoRMI);
System.out.println("Registro RMI creado en el puerto " + numPuertoRMI);
} //fin catch
} //fin arrancarRegistro
/**
* Listar los nombres registrados con un objeto Registry
*/
private static void listarRegistro(String URLRegistro) throws RemoteException,
MalformedURLException {
System.out.println("Registro " + URLRegistro + " contiene: ");
String[] nombres = Naming.list(URLRegistro);
for (int i = 0; i<nombres.length; i++)
System.out.println(nombres[i]);
} //fin listaRegistro
} //fin class

Listado 52: HolaMundoCliente.java haciendo uso de un gestor de seguridad.

69

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

import java.io.*;
import java.rmi.*;
/**
* Clase que representa el cliente de un objeto distribuido de clase HolaMundo,
* que implementa la interfaz remota HolaMundoInt.
*/
public class HolaMundoCliente {
public static void main (String[] args) {
try {
int numPuertoRMI;
String nombreNodo;
InputStreamReader ent = new InputStreamReader(System.in);
BufferedReader buf = new BufferedReader(ent);
System.out.println("Introducir el nombre del nodo del registro RMI:");
nombreNodo = buf.readLine();
System.out.println("Inroducir el nmero de puerto del registro RMI:");
String numPuerto = buf.readLine();
numPuertoRMI = Integer.parseInt(numPuerto);
// Arrancar un gestor de seguridad - esto es necesario si se utiliza
// la descarga de resguardo
System.setSecurityManager(new RMISecurityManager());
String URLRegistro = "rmi://" + nombreNodo + ":" + numPuerto + "/holaMundo";
//Buscar objeto remoto
HolaMundoInterfaz h = (HolaMundoInterfaz)Naming.lookup(URLRegistro);
System.out.println("Bsqueda completa");
//Invocar mtodo remoto
String mensaje = h.decirHola("Pato Donald");
System.out.println("HolaMundoCliente: " + mensaje);
} //fin try
catch (Exception e) {
e.printStackTrace();
}
} //fin main
} //fin class

La sintaxis de un fichero de polticas de seguridad de Java


Es un fichero de texto que contiene cdigos que permiten especificar la concesin de permisos
especficos. A continuacin se muestra un fichero tpico java.policy para una aplicacin RMI.
grant {
// Este permiso permite a los clientes RMI realizar conexiones de sockets
// a los puertos pblicos de cualquier computador.
// Si se arranca un puerto en el registro RMI en este rango, no existir
// violacin de acceso de conexin.
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 aplicacin
con el nombre java.policy en el mismo directorio tanto en la mquina del cliente como en la
mquina del servidor de objeto.
Cuando se active el cliente, hay que utilizar la opcin del mandato que permite especificar
que el proceso cliente debe tener los permisos definidos en el fichero de polticas, de la siguiente
forma:
java -Djava.security.policy=java.policy ClienteEjemplo
Del mismo modo, el servidor debe activarse as:
java -Djava.security.policy=java.policy ServidorEjemplo

70

Uso de descarga de resguardo y un fichero de polticas de seguridad


1. Si debe descargarse el resguardo de un servidor HTTP, transfiera la clase resguardo a
un directorio apropiado del servidor HTTP, y asegrese de que el permiso de acceso del
fichero 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=<fichero
de polticas> <Aplicacin Java>
Algoritmos para construir una aplicacin 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 aplicacin.
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 implementacin 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 implementacin 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 apropiado
del servidor HTTP.
7. Si se utiliza el registro RMI y no ha sido ya activado, activarlo. Por ejemplo: rmiregistry
<nmero de puerto>. Alternativamente, se puede codificar la activacin en el programa
del servidor de objeto.
8. Construir un fichero de polticas de seguridad para la aplicacin denominado java.policy y
colocarlo en un directorio apropiado.
9. Activar el servidor, especificando (1) el campo codebase si se utiliza descarga de resguardo,
y (2) el fichero de polticas de seguridad.
Algoritmo para desarrollar el software de la parte cliente
1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicacin.
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 resguardo
y colocarlo en el directorio actual.
5. Construir un fichero de polticas de seguridad para la aplicacin denominado java.policy y
colocarlo en un directorio apropiado.
6. Activar el cliente, especificando el fichero de polticas de seguridad.

71

10.

CORBA - Common Object Request Broker Architecture

Se presentar una arquitectura alternativa para objetos distribuidos. Se la conoce como Common Object Request Broker Architecture (CORBA). CORBA en primer lugar, proporciona un
caso de estudio que ilustra dos arquitecturas similares, pero en contraste, para un concepto
determinado, los objetos distribuidos. En segundo lugar, proporciona un ejemplo de una arquitectura diseada para alcanzar la mxima interoperabilidad.
CORBA es una arquitectura que permite que objetos distribuidos interoperen sobre entornos heterogneos, donde los objetos pueden estar implementados en diferentes lenguajes de
programacin y/o desplegados sobre diferentes plataformas.

10.1.

Arquitectura bsica

La Figura 22 muestra la arquitectura bsica de CORBA. Guarda una gran semejanza con la
arquitectura RMI. Un cliente de objeto realiza una llamada a un mtodo de un objeto distribuido. El cliente interacta con un proxy, un stub, mientras que la implementacin del objeto
interacta con un proxy de servidor, un skeleton. Una capa adicional de software, conocida como ORB (Object Request Broker) es necesaria. En el lado del cliente, la capa del ORB acta
como intermediaria entre el stub y la red y el sistema operativo local del cliente. En el lado del
servidor, la capa del ORB sirve de intermediaria entre el skeleton y la red y sistema operativo del
servidor. Las capas ORB de ambos extremos son capaces de resolver las diferencias existentes en
lo referente a lenguajes de programacin, as como las relativas a las plataformas, para ayudar a
la comunicacin entre los dos extremos. El cliente utiliza un servicio de nombrado para localizar
el objeto.

Figura 22: Arquitectura CORBA bsica.

10.2.

La interfaz de objetos de CORBA

Debido a que CORBA es independiente de lenguaje, la interfaz se define por medio de un


lenguaje universal con una sintaxis especfica, conocido como CORBA Interface Definition Language (IDL). La sintaxis de CORBA IDL es muy similar a la de Java, pero un objeto definido en
CORBA IDL puede implementarse en un gran nmero de lenguajes. Para cada uno de estos lenguajes, OMG tiene una traduccin estndar de CORBA IDL a dicho lenguaje de programacin,
de forma que se pueda usar un compilador para procesar las interfaces CORBA y generar los
proxies necesarios.
La Figura 23 muestra una aplicacin donde el cliente es un programa escrito en Java mientras
que el objeto est implementado en C++.

Figura 23: Independencia de mensajes en CORBA.

72

10.3.

Protocolos inter-ORB

Para que dos ORB puedan interoperar, OMG ha especificado un protocolo conocido como
GIOP. Un caso especial de este protocolo es el Internet Inter-ORB Protocol (IIOP), que se
corresponde con el GIOP aplicado sobre el nivel de transporte de TCP/IP.
La especificacin de IIOP incluye los siguientes elementos:
1. Requisitos de gestin de transporte. Especifican qu se necesita para conectarse y desconectarse, y los papeles que el cliente y el objeto servidor interpretan.
2. Definicin de la representacin comn de datos. Se necesita definir un esquema de codificacin 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 tipos
de mensajes. Cada cliente usa un mensaje de peticin para invocar a un mtodo declarado
en la interfaz CORBA de un objeto y recibe un mensaje de respuesta del servidor.
Un ORB que soporte la especificacin de IIOP puede interoperar con otro ORB compatible IIOP
a travs de Internet. De aqu surje la denominacin bus de objetos: Internet se ve como un bus
de 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 obtiene la referencia a un objeto distribuido por medio de un servicio de nombres o de directorio
y posteriormente invoca los mtodos de dicho objeto distribuido.

10.5.

Referencias a objetos CORBA

Un objeto distribuido CORBA se localiza por medio de una referencia a objeto. Una referencia a un objeto CORBA es una entidad abstracta traducida a una referencia de objeto especfica
de cada lenguaje por medio del ORB.
OMG especifica un protocolo para referencias abstractas de objetos, conocido como protocolo
Interoperable Object Reference (IOR). Un ORB compatible con el protocolo IOR permitir que
una referencia a objeto se registre y se obtenga desde un servicio de directorio compatible con
IOR.
Una IOR es una cadena de caracteres que contiene codificada la informacin siguiente:
El tipo de objeto.
El ordenador donde se encuentra el objeto.
El nmero de puerto del servidor de objeto.
Una clave del objeto, una cadena de bytes que identifica al objeto. La utiliza el servidor de
objetos para localizar el objeto internamente.
La representacin consiste en un prefijo con los caracteres IOR: seguido por una secuencia hexadecimal de caracteres numricos, donde cada carcter representa 4 bits de datos binarios en la
IOR.

10.6.

Servicio de nombres y servicio de nombres interoperable en CORBA

En el Captulo 7 se present el registro RMI como un servicio de directorio distribuido para


objetos RMI. CORBA especifica un servicio de directorio con el mismo propsito. El servicio
de nombres sirve como un directorio de objetos CORBA, independiente de la plataforma y del
lenguaje de programacin.

73

Servicio de nombres de CORBA


El Servicio de Nombres permite que clientes basados en ORB obtengan las referencias a los
objetos que desean usar. Permite asociar nombres a referencias de objetos.
Para exportar un objeto distribuido, un servidor de objetos CORBA contacta con el Servicio
de Nombres para asociar (bind) un nombre simblico al objeto. Para obtener una referencia a un
objeto, un cliente de objetos solicita que el Servicio de Nombres busque el objeto asociado con
dicho nombre. El API para el Servicio de Nombres se encuentra especificada por medio de una
interfaz IDL, que incluye mtodos que permiten a servidores asociar nombres a objetos y a los
clientes resolverlos.
Se define una jerarqua de nombrado estndar de una manera similar a un directorio de
ficheros. En este esquema de nombrado, un contexto de nombrado se corresponde con una
carpeta o directorio en un rbol de ficheros, mientras que los nombres de objetos se corresponden
con 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 de
nombrado>.. . . <contexto de nombrado>.<nombre del objeto>. La Figura 24 muestra un ejemplo de
una jerarqua de nombrado.

Figura 24: Un ejemplo de la jerarqua de nombrado de CORBA.

Servicio de nombres interoperable de CORBA


El Interoperable Naming Service (INS) es un sistema de nombrado basado en el formato URL
para el Servicio de Nombres de CORBA. Permite que las aplicaciones compartan un contexto
inicial de nombrado y que proporcionen un URL para acceder a un objeto CORBA. Utilizando
este sistema, un URL del tipo corbaname::acme.com:2050#tienda/ropa/mujer se podra usar para
acceder al objeto tienda/ropa/mujer del servicio de nombres en el puerto 2050 del servidor con
nombre acme.com.

10.7.

Servicios de objetos CORBA

Dentro de las especificaciones de CORBA se encuentran varias que proporcionan servicios


usados habitualmente por los objetos distribuidos para construir aplicaciones. Algunos de los
servicios son:
Servicio de concurrencia proporciona control de concurrencia.
Servicio de eventos para la sincronizacin de eventos.
Servicio de log para registrar eventos.
Servicio de nombres servicio de directorio.
Servicio de planificacin para planificacin de eventos.

74

Servicio de seguridad para gestin de seguridad.


Servicio de negociacin para localizar servicios por tipo.
Servicio de tiempo un servicio para eventos relativos al tiempo.
Servicio de notificacin para notificacin de eventos.
Servicio de transacciones de objetos para procesamiento de transacciones.
Cada servicio se define por medio de un IDL estndar que puede ser implementado por los
desarrolladores, y los mtodos del objeto de servicio se pueden invocar desde cualquier cliente
CORBA.

10.8.

Adaptadores de objetos

En la arquitectura de CORBA, la implementacin de objetos distribuidos acta con el skeleton


para conectarse con el stub en el lado del cliente. Cuando evolucion, se aadi un componente
software al skeleton en el lado del servidor: el adaptador de objetos. Un adaptador de objetos
simplifica las responsabilidades que tiene un ORB asistindole en hacer llegar las peticiones del
cliente a la implementacin del objeto.
Hay diferentes tipos de adaptadores de objetos CORBA. El Portable Object Adapter (POA)
permite que una implementacin de objeto funcione en varios ORB, de forma que la implementacin del objeto sea portable a travs 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 un


subconjunto de los servicios estndar de CORBA. En el resto de este captulo, se tratar Java
IDL 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 soporte
a CORBA:
El paquete org.omg.CORBA contiene las interfaces y las clases que proporcionan la traduccin de las API de CORBA OMG al lenguaje de programacin Java.
El paquete org.omg.CosNaming contiene los interfaces y las clases que dan soporte al Servicio 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 lnea de comandos para que los programadores
de aplicaciones puedan registrar/desregistrar objetos, y arrancar/parar servidores.
tnameserv versin antigua del Servicio de Nombrado (desaconsejado).
Una aplicacin CORBA de ejemplo
El ejemplo muestra un objeto CORBA que proporciona un mtodo que devuelve la cadena
de caracteres Hola mundo.

75

Fichero de la interfaz CORBA El punto de arranque de una aplicacin CORBA es el desarrollo


del fichero de interfaz CORBA escrito en el IDL de OMG. La sintaxis de este fichero de interfaz
es la misma independientemente de cules sean las herramientas CORBA utilizadas. El Listado
53 muestra un ejemplo de un posible fichero IDL que declara la interfaz llamada Hola. El mtodo
apagar() 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 mdulo. El modificador oneway
denota que el mtodo apagar requiere slo una comunicacin del cliente al servidor (y ninguna
respuesta del servidor).
El fichero IDL puede colocarse en un directorio dedicado para esta aplicacin. El fichero se
compila usando el compilador idlj de la siguiente forma:
idlj -fall Hola.idl

Listado 53: Hola.idl


1
2
3
4
5
6

module HolaApp {
interface Hola {
string decirHola();
oneway void apagar();
}
}

La opcin -fall es necesaria para que el compilador genere todos los ficheros necesarios para
el resto del ejemplo. Si la compilacin tiene xito se generan los siguientes ficheros:
HolaOperations.java
Hola.java
HolaHelper.java
HolaHolder.java
_HolaStub.java
HolaPOA.java
Estos ficheros no necesitan ninguna modificacin por su parte. Se explicar brevemente cada
uno de estos ficheros en los siguientes prrafos.
HolaOperations.java, el interfaz de operaciones Este fichero (Listado 54), conocido como interfaz de operaciones Java, traduce el fichero de interfaz IDL CORBA. Contiene los mtodos
definidos en el fichero IDL original.
Listado 54: HolaApp/HolaOperations.java
1
2
3
4
5
6

package HolaApp;
public interface HolaOperations {
String decirHola();
void apagar();
}

Hola.java, el fichero de forma de interfaz Este fichero (Listado 55), denominado fichero de
firma de interfaz, extiende clases de CORBA y la interfaz especfica de la aplicacin, HolaOperations.
Listado 55: HolaApp/Hola.java
1
2
3

package HolaApp;
public interface Hola extends HolaOperations, org.omg.CORBA.Object, org.omg.CORBA.
portable.IDLEntity {}

76

HolaHelper.java, la clase de ayuda La clase HolaHelper (Listado 56), proporciona funcionalidades auxiliares necesarias para dar soporte a los objetos CORBA en el contexto del lenguaje
de programacin Java. Un mtodo, narrow, permite que una referencia a un objeto CORBA se
pueda convertir a su tipo correspondiente en Java. La descripcin detallada del fichero est ms
all del mbito de este libro.
Listado 56: HolaApp/HolaHelper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package HolaApp;
abstract public class HolaHelper {
private static String _id = "IDLHolaApp/Hola1.0";
public static void insert (org.omg.CORBA.any a, HolaApp.Hola that) {
org.omg.CORBA.portable.OutputStream out = a.create_output_stream();
a.type(type());
write(out, that);
a.read_value(out.create_input_stream(), type());
}
public static HolaApp.Hola extract(org.omg.CORBA.Any a) {
return read(a.create_input_stream());
}
private static org.omg.CORBA.TypeCode _typeCode = null;
synchronized public static org.omg.CORBA.TypeCode type() {
if(_typeCode == null) {
_typeCode = org.omg.CORBA.ORB.init().create_interface_tc(HolaApp.HolaHelper.
id(), "Hola");
}
return _typeCode;
}

21
22
23
24
25
26
27
28
29
30
31
32
33

public static String id() {


return _id;
}
public static HolaApp.Hola read(org.omg.CORBA.portable.InputStream istream) {
return narrow(istream.read_Object(_HolaStub.class));
}
public static void write(org.omg.CORBA.portable.OutputStream ostream, HolaApp.Hola
value) {
ostream.write_Object((org.omg.CORBA.Object)value);
}

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

public static HolaApp.Hola narrow(org.omg.CORBA.Object obj) {


if(obj==null)
return null;
else if(obj instanceof HolaApp.Hola)
return (HolaApp.Hola)obj;
else if(!obj._is_a(id()))
throw new org.omg.CORBA.BAD_PARAM();
else {
org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.
ObjectImpl)obj)._get_delegate();
HolaApp._HolaStub stub = new HolaApp._HolaStub();
stub._set_delegate(delegate);
return stub;
}
}
}

HolaHolder.java, la clase contenedora La clase HolaHolder (Listado 57), contiene una referencia
al objeto que implementa la interfaz Hola. La clase proyecta los parmetros de tipo out o inout
del IDL a la sintaxis de Java.
Listado 57: HolaApp/HolaHolder.java

77

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package HolaApp;
public final class HolaHolder implements org.omg.CORBA.portable.Streamable {
public HolaApp.Hola value = null;
public HolaHolder() {}
public HolaHolder(HolaApp.Hola initialValue) {
value = initialValue;
}
public void _read(org.omg.CORBA.portable.InputStream i) {
value = HolaApp.HolaHelper.read(i);
}
public void _write(org.omg.CORBA.portable.OutputStream o) {
HolaApp.HolaHelper.write(o, value);
}
public org.omg.CORBA.TypeCode _type() {
return HolaApp.HolaHelper.type();
}
}

_HolaStub.java, el fichero de resguardo (stub) La clase _HolaStub (Listado 58) es el fichero de


resguardo o stub, el proxy de cliente, que interacta con el objeto cliente.
Listado 58: HolaApp/_HolaStub.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

package HolaApp;
public class _HolaStub extends org.omg.CORBA.portable.ObjectImpl implements HolaApp.
Hola {
public String decirHola() {
org.omg.CORBA.portable.OutputStream $in = null;
try {
org.omg.CORBA.portable.OutputStream $out = _request("decirHola", true);
$in = _invoke($out);
String $result = $in.read_string();
return $result;
} catch (org.omg.CORBA.portable.ApplicationException $ex) {
$in = $ex.getInputStream();
String _id = $ex.getId();
throw new org.omg.CORBA.MARSHAL(_id);
} catch (org.omg.CORBA.portable.RemarshalException $rm) {
return decirHola();
} finally {
_releaseReply($in);
}
}
public void apagar() {
org.omg.CORBA.portable.InputStream $in = null;
try {
org.omg.CORBA.portable.OutputStream $out = _request("apagar", false);
$in = _invoke($out);
} catch (org.omg.CORBA.portable.ApplicationException $ex) {
$in = $ex.getInputStream();
String _id = $ex.getId();
throw new org.omg.CORBA.MARSHAL(_id);
} catch (org.omg.CORBA.portable.RemarshalException $rm) {
apagar();
} finally {
_releadeReply($in);
}
}
private static String[] _ids = {"IDLHolaApp/Hola1.0"};
public String _ids() {
return (String[])_ids.clone();

78

42
43
44
45
46
47
48

private void readObject(java.io.ObjectInputStream s) throws java.io.IOException {


String str = s.readUTF();
String[] args = null;
java.util.Properties props = null;
org.omg.CORBA.Object obj = org.omg.CORBA.ORB.init(args, props).string_to_object
(str);
org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)
obj)._get_delegate();
_set_delegate(delegate);
}

49
50
51
52
53
54
55
56
57
58
59
60

private void writeObj(java.io.ObjectOutputStream s) throws java.io.IOException {


String[] args = null;
java.util.Properties props = null;
String str = org.omg.CORBA.ORB.init(args, props).object_to_string(this);
s.writeUTF(str);
}
}

HolaPOA.java, el skeleton del servidor y el adaptador de objetos POA La clase HolaPOA


(Listado 59) es la combinacin del skeleton (proxy asociado al servidor) con el adaptador de
objetos POA (Portable Object Adapter).
Listado 59: HolaApp/HolaPOA.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package HolaApp;
public abstract class HolaPOA extends org.omg.PortableServer.Servant implements
HolaApp.HolaOperations, org.omg.CORBA.portable.InvokeHandler {
private static java.util.Hashtable _methods = new java.util.Hashtable();
static {
_methods.put("decirHola", new java.lang.Integer(0));
_methods.put("apagar", new java.lang.Integer(1));
}
public org.omg.CORBA.portable.OutputStream _invoke(String $method, org.omg.CORBA.
portable.InputStream in, org.omg.CORBA.portable.ResponseHandler $rh) {
org.omg.CORBA.portable.OutputStream out = null;
java.lang.Integer _method = (java.lang.Integer)_methods.get($method);
if(_method == null)
throw new org.omg.CORBA.BAD_OPERATION(0, org.omg.CORBA.CompletionStatus.
COMPLETED_MAYBE);

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

switch(_method.intValue()) {
case 0 {
String $result = null;
$result = this.decirHola();
out = $rh.createReply();
out.write_string($result);
break;
}
case 1 {
this.apagar();
out = $rh.createReply();
break;
}
default {
throw new org.omg.CORBA.BAD_OPERATION(0, org.omg.CORBA.CompletionStatus.
COMPLETED_MAYBE);
}
}
return out;
}
private static String[] _ids = {"IDLHolaApp/Hola1.0"};
public String[] _all_interfaces(org.omg.PortableServer.POA poa, byte[] objectId) {

79

40
41
42
43
44
45
46
47
48
49
50
51

return(String[])_ids.clone();
}
public Hola _this() {
return HolaHelper.narrow(super._this_object());
}
public Hola _this(org.omg.CORBA.ORB orb) {
return HolaHelper.narrow(super._this_object(orb));
}
}

La aplicacin A continuacin se van a ver los ficheros fuente de la aplicacin que s debe
desarrollar 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 definicin de cada mtodo
declarado en la interfaz IDL.
Listado 60: HolaApp/HolaImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

import
import
import
import
import
import
import

HolaApp.*;
org.omg.CosNaming.*;
org.omg.CosNaming.NamingContextPackage.*;
org.omg.CORBA.*;
org.omg.PortableServer.*;
org.omg.PortableServer.POA;
java.util.Properties;

/**
* El servant (implementacin del objeto) para el ejemplo.
*/
class HolaImpl extends HolaPOA {
private ORB orb;
public void setORB(ORB orb_val) {
orb = orb_val;
}
public String decirHola() {
return "\nHola mundo!\n";
}
public void apagar() {
org.apagar(false);
}
}

El servidor (Listado 61) es el responsable de crear e inicializar el ORB, activar el gestor del
adaptador de objetos POA, crear una instancia de la implementacin del objeto, y de registrar el
objeto en el ORB.
Listado 61: HolaApp/ServidorHola.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14

import
import
import
import
import
import
import

HolaApp.*;
org.omg.CosNaming.*;
org.omg.CosNaming.NamingContextPackage.*;
org.omg.CORBA.*;
org.omg.PortableServer.*;
org.omg.PortableServer.POA;
java.util.Properties;

/**
* Un servidor para el objeto Hola
*/
public class ServidorHola {
public static void main (String[] args) {
try {

80

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

ORB orb = ORB.init(args, null);


POA rootpoa = (POA)orb.resolve_initial_references("RootPOA");
rootpoa.the_POAManager().activate(); //activar POAManager
HolaImpl holaImpl = new HolaImpl();
holaImpl.setORB(orb); //registrar servant en el ORB
// obtener referencia de objeto del servant
org.omg.CORBA.Object ref = rootpoa.servant_to_reference(holaImpl);
// convertirla en una referencia CORBA
Hola href = HolaHelper.narrow(ref);
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
String name = "Hola";
NameComponent path[] = ncRef.to_name(name);
ncRef.rebind(path, href);
System.out.println("ServidorHola preparado...");
orb.run();
} catch (Exception e) {
System.err.println("ERROR " + e);
e.printStackTrace();
}
System.out.println("ServidorHola saliendo...");
}
}

La aplicacin cliente del objeto El Listado 62 muestra un ejemplo de cliente para el objeto
Hola. El cdigo cliente se debe encargar de crear e inicializar el ORB, buscar el objeto usando el
Servicio de Nombrado Interoperable, invocar el mtodo narrow del objeto Helper para convertir
la referencia del objeto a una referencia de una implementacin del objeto Hola, e invocar los
mtodos remotos usando dicha referencia.
Listado 62: HolaApp/ClienteHola.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

import
import
import
import

HolaApp.*;
org.omg.CosNaming.*;
org.omg.CosNaming.NamingContextPackage.*;
org.omg.CORBA.*;

/**
* Ejemplo de aplicacin cliente del objeto.
*/
public class ClienteHola {
static Hola holaImpl;
public static void main (String[] args) {
try {
ORB orb = ORB.init(args, null);
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
String nombre = "Hola";
holaImpl = HolaHelper.narrow(ncRef.resolve_str(nombre));
System.out.println("Obtenido un manejador para el objeto servidor " +
holaImpl);
System.out.println(holaImpl.decirHola());
holaImpl.apagar();
} catch (Exception e) {
System.err.println("ERROR " + e);
e.printStackTrace(System.out);
}
}
}

81

Compilacin y ejecucin de una aplicacin Java IDL


Procedimiento para compilar y ejecutar aplicaciones Java IDL.
Parte servidora
1. Colquese 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 opcin
-fall para generar todo el cdigo de soporte cliente y servidor, el cual se guardar en el
subdirectorio HolaApp.
3. Compile los ficheros .java del directorio HolaApp, incluyendo los stubs y los skeletons, mediante el comando javac *.java HolaApp/*.java.
4. Arranque el Ddemonio de ORB Java, orbd, que incluye el servidor del Servicio de Nombrado.
En Unix/Linux: orbd -ORBInitialPort <puerto>&.
En Win: start orbd -ORBInitialPort <puerto>&.
5. Arranque el servidor Hola.
En Unix/Linux: java ServidorHola -ORBInitialPort <puerto> -ORBInitialHost
localhost.
En Win: start java ServidorHola -ORBInitialPort <puerto> -ORBInitialHost
localhost.
Parte cliente
1. Obtenga y compile el fichero Hola.idl de la mquina servidora: idlf -fall Hola.idl.
Copie el directorio y el subdirectorio creados con sus contenidos a la mquina cliente.
2. En el directorio HolaApp de la mquina cliente, cree el fichero ClienteHola.java. Compile los
ficheros .java, incluyendo los stubs y los skeletons: javac *.java HolaApp/*.java.
3. Ejecute la aplicacin 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. La
misma posibilidad existe en el caso de Java IDL.

82

11.

Servicios web/Aplicaciones de Internet

Un servicio web es una pieza software que dispone de una funcionalidad especfica y que
permite ser empleada en multitud de entornos con independencia del lenguaje de desarrollo. El
xito del modelo web puede atribuirse a que es un modelo ms dbilmente acoplado que los
modelos de programacin distribuida tradicionales como RPC, RMI o CORBA. Los clientes y
servidores web intercambian mensajes que transportan datos de tipo MIME. El destino de un
mensaje se especifica indirectamente utilizando una URL.
La idea bsica de los servicios web es adaptar el modelo de programacin web dbilmente
acoplado a su uso en aplicaciones que no estn basadas en el navegador. El objetivo es proporcionar una plataforma para construir aplicaciones distribuidas utilizando software que se ejecute
entre distintos sistemas operativos, escrito en diferentes lenguajes de programacin.

11.1.

Qu es un servicio web?

Un servicio web representa un recurso de informacin o un proceso de negocio, al cual otra


aplicacin puede acceder a travs de la web, y con el cual se puede comunicar a travs de
protocolos estndar de Internet.
Los servicios web estn diseados para soportar la comunicacin de una aplicacin con otra
aplicacin. Otros tipos de aplicaciones web soportan comunicacin entre personas o comunicacin persona-aplicacin. Los servicios web estn diseados para permitir que las aplicaciones se
comuniquen sin intervencin humana.
Arquitectura de los servicios web (WSA)
Los principios de diseo de las aplicaciones distribuidas basadas en servicios web tienen
su erigen en la Arquitectura Orientada a Servicios (SOA). Ejemplos de esta arquitectura se
encuentran en tecnologas como RPC, RMI o CORBA. En la Figura 25 se muestra este modelo
arquitectnico. Sus tres componentes fundamentales son:
1. Proveedor del servicio, encargado de hacer que el servicio est disponible. Debe publicar
un contrato que describa la interfaz del servicio que ofrece y registrarlo en el agente de
servicio.
2. Cliente del servicio, que busca el servicio que necesita a travs del agente de servicio.
3. Agente del servicio, que ofrece a los clientes un mecanismo de bsqueda de los servicios
previamente registrados. El agente le da al cliente las direcciones donde puede encontrar
el servicio que necesita y el contrato del mismo.

Figura 25: Arquitectura SOA.

Adems, un sistema que implemente este modelo debe soportar tres funcionalidades bsicas:
83

1. Transporte, es decir cmo se representan los formatos y protocolos usados para comunicarse con un servicio.
2. Descripcin, encargada de definir y usar un lenguaje de descripcin adecuado para el
servicio. A partir de ste lenguaje es posible generar de forma dinmica y esttica el cdigo
de comunicacin, as como los delegados y esqueletos necesarios.
3. Descubrimiento, que se encarga de representar el mecanismo usado para registrar o encontrar un servicio y su contrato o descripcin.
A partir de SOA nace la Arquitectura de Servicios Web (WSA), mostrada en la Figura 26 y
que converge el modelo SOA y el uso de web como modelo de comunicacin. Su caracterstica
principal es que es independiente de la plataforma y del lenguaje.

Figura 26: Modelo arquitectnico WSA.

El protocolo bsico de los servicios web es XML, que se usa como formato de los mensajes de
datos y como base de otros protocolos de WSA, tales como SOAP, WSDL y UDDI. La utilizacin
de XML garantiza la independencia del lenguaje y de la plataforma. XML por s solo no puede
implementar los protocolos de comunicacin puesto que las aplicaciones necesitan formatos
estndares y protocolos que permitan interpretar de forma apropiada los datos XML. Se han
desarrollado tres estndares de facto:
Protocolo Simple de Acceso a Objeto (SOAP). Define un protocolo estndar de comunicacin para los servicios web.
Lenguaje de Descripcin de Servicios web (WSDL). Define un mecanismo estndar para
describir un servicio web.
Servicio de descripcin Universal, Descubrimiento e Integracin (WSDL). Proporciona un
mecanismo estndar para registrar y encontrar servicios web.
En la Figura 27 se muestra la relacin entre las tecnologas descritas aplicadas al modelo SOA.

11.2.

Funcionalidad de transporte de WSA: SOAP.

SOAP es un protocolo de mensajera basado en XML extensible que forma la base de los
servicios web. SOAP permite a una aplicacin enviar un mensaje XML a otra aplicacin. Bsicamente SOAP est compuesto de cuatro partes:
Envoltorio SOAP (envelope). Proporciona un mecanismo de identificacin de los contenidos
del mensaje y decide cmo se debe procesar el mensaje. Se compone a su vez de dos partes:
la cabecera SOAP y el cuerpo SOAP. La cabecera permite aadir informacin de control o
directivas de mensaje, y se puede usar para implementar lgica asociada a:
84

Figura 27: Relacin entre SOAP, WSDL y UDDI.

Transacciones.
Seguridad.
Fiabilidad.
Redireccionamiento.
Mecanismos de facturacin.
Cuerpo SOAP (body). Transporta la carga til que ser enviada con el mensaje SOAP. Puede
corresponder a un documento XML o a una invocacin remota.
Marco de trabajo de enlace de transporte SOAP. Define el mecanismo de transporte que se
puede usar al enlazar un cliente con un servicio web. El enlace por defecto es el protocolo
HTTP, pero se pueden usar SMTP, JMS, etc.
Marco de trabajo de Serializacin SOAP. Es necesario definir cmo se realiza la codificacin de los mensajes XML. Este marco define si los datos se pasan como un documento
XML normal, si se le aplica alguna codificacin, o si se usan las reglas originales definidas
para SOAP.
Tipos de mensajes SOAP
Existen dos tipos de mensajes SOAP:
Mensajes de tipo RPC. Usando RPC, el desarrollador formula una peticin SOAP como
un mtodo con cero o ms parmetros. Cuando se construye el cuerpo del mensaje SOAP,
se representa el mtodo en una estructura simple donde el elemento (etiqueta) ms exterior est representado por el nombre del mismo, y los elementos internos representan los
parmetros de la operacin. La respuesta SOAP es similar, donde sus elementos internos
representan los resultados devueltos.
Mensajes de tipo Documento. Permite enviar documentos XML. El emisor es el que enva
el mensaje y el receptor determina qu hacer con l. El emisor slo necesita saber cul es
el formato del mensaje y el punto de acceso (normalmente un URI).
Tambin existe una especificacin de mensaje que permite incluir archivos no XML a los mensajes. Se pueden as aadir archivos multimedia no codificados con XML.

11.3.

Funcionalidad de descripcin de WSA: WSDL

WSDL describe un servicio web: qu funcionalidad ofrece, cmo se comunica y dnde es


accesible. Proporciona un mecanismo estructurado que describe:
85

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 descripcin WSDL define una coleccin de puntos de acceso a red o puertos. Cada puerto se
define de forma abstracta con su tipo, que soporta un conjunto de operaciones. Cada operacin
procesa un conjunto particular de mensajes. Un enlace (binding) relaciona un tipo de puerto con
un 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. Soporta datos simples y estructuras complejas, que pueden ser relacionados directamente
con sus tipos correspondientes en los lenguajes de programacin. Las herramientas SOAP
usan la informacin 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 como
estructuras de entrada o salida para las operaciones soportadas. Pueden estar compuestos
por 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 elemento u operacin (etiqueta <operation>) define los mensajes de entrada y salida asociados a la operacin.
4. Enlace (etiqueta <binding>). Un elemento enlace relaciona las operaciones y mensajes
definidos por un tipo de puerto a un protocolo concreto y una especificacin de formato
de datos. Por ejemplo, puede asociar un tipo de puerto a un interfaz especfica que usa el
protocolo HTTP para el transporte y el sistema de codificacin de datos SOAP.
5. Servicio (etiqueta <service>). Define una coleccin de puertos (etiqueta <port>) relacionados. Un puerto a su vez relaciona un enlace con la localizacin (URL) de una instancia
del 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 interfaz
abstracta del servicio web. Describe un tipo de servicio: conjunto de operaciones que implementa el servicio.
2. Enlace concreto. Se denomina parte cmo y describe la asociacin de la interfaz abstracta
con un conjunto concreto de protocolos. Incluye o importa la parte qu del documento
WSDL asociado.
3. Implementacin. Se denomina parte dnde y describe la implementacin del servicio. Un
proveedor de servicio siempre debe publicar la parte dnde del documento WSDL con el
servicio web.

Figura 28: Partes de un documento WSDL.

86

En la Figura 29 se puede ver la descripcin de un servicio web de ejemplo disponible en la


direccin web de la empresa XMethods Inc. Se presenta el servicio web que define el cambio de
moneda para diferentes pases.

Figura 29: Descripcin WSDL del servicio de cambio de moneda.

Como se puede apreciar en la Figura 29, hay dos tipos de mensajes SOAP RPC: uno de peticin (<message name="getRateRequest">) y uno de recepcin (<message name="getRateResponse">)
que usan el estilo de documento RPC con las reglas de codificacin dadas por el esquema de
tipos del W3C (etiquetas xsd:string y xsd:float).
Para cada mensaje definido en la descripcin WSDL se generan dos mensajes SOAP RPC,
una para el de peticin (Listado 63) y otro para la respuesta (Listado 64). En el caso del mensaje
de peticin el cuerpo tiene un elemento ms externo con el nombre del mtodo (getRate) y dos
elementos ms externos (country1 y country2) con los parmetros del mtodo y sus valores (Euro
y USA).
<SOAP-ENV:Envelope
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>
<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

</ns1:getRate>
</SOAP-ENV:Body>
Listado 63: Mensaje SOAP RPC de peticin del valor de cambio de moneda.

En el mensaje de respuesta (getRateResponse) slo es necesario devolver un valor del dato


pedido.
<SOAP-ENV:Envelope
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>
<ns1:getRateResponse xmlns:ns1="urn:xmethods-CurrencyExchange" SOAPENV: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 elemento enlace permite relacionar el servicio con un protocolo especfico, mientras que el elemento
servicio relaciona el tipo de servicio y el enlace a una instancia especfica del servicio. Los elementos enlace y servicio pueden ser mantenidos en documentos WSDL distintos con el fin de
obtener ms flexibilidad.

11.4.

Funcionalidad de descubrimiento de WSA: UDDI

UDDI proporciona un mecanismo para registrar y categorizar los distintos servicios web que
se pueden ofertar a los clientes y que stos deben poder localizar a travs de dicho mecanismo.
Como adems UDDI es un servicio web a su vez, se pueden usar mensajes SOAP para usarlo.
El registro UDDI contiene la informacin sobre los negocios y los servicios que ofrecen. Se
puede organizar de la siguiente manera:
Entidad de negocio. Informacin sobre el negocio (nombre, descripcin, contacto). Cada
negocio tiene asociado un identificador nico y una lista de categoras que lo describen.
Servicio de negocio. Lista de servicios ofertados por la entidad. Cada uno de ellos contiene
una descripcin del servicio, una lista con las categoras asociadas y una lista de patrones
de enlace que contienen informacin tcnica sobre el servicio.
Patrones de enlace. Proporcionan informacin sobre cmo usar el servicio y dnde encontrarlo. Adems asocian el servicio de negocio con un tipo de servicio.
Tipo de servicio. Define un servicio de forma abstracta a travs de una estructura llamada
tModel. 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 forma
abstracta.
Cuando se necesita utilizar un servicio web, un desarrollador hace una bsqueda en el registro
UDDI, especificando el tipo de servicio que se desea. De la entrada para el tipo de servicio del
tModel, se puede obtener una descripcin WSDL para la interfaz del servicio. De la entrada/s del
patrn de enlace se puede obtener el enlace al servicio y el punto de acceso. Para acabar, usando
la descripcin WSDL es posible construir una interfaz de cliente SOAP que se puede comunicar
con el servicio web. En la Figura 30 se puede apreciar que existen dos entradas de patrones de
enlace 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 aplicacin cliente de dos maneras:
1. De forma esttica. Se puede usar la parte cmo del documento WSDL y generar una interfaz
de cliente SOAP o un proxy que implemente el enlace requerido para comunicarse con una
implementacin de servicio especfica.

88

2. De forma dinmica. Se puede usar el enlace dinmico. De esta forma usando la parte
qu del documento WSDL se puede generar la interfaz abstracta del cliente SOAP que
puede trabajar con cualquier implementacin de un tipo de servicio especfico. En tiempo
de ejecucin la aplicacin cliente puede compilar la parte dnde del documento WSDL y
generar un proxy dinmico que implemente el enlace.

Figura 30: Descripcin 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 flexibilidad y la alta escalabilidad que puede ofrecer UDDI. Adems, UDDI permite localizar servicios
no slo por el nombre, sino tambin por otras caractersticas como pueden ser versiones, informacin geogrfica, etc.

11.5.

Implementacin de la arquitectura WSA

Se pueden utilizar los servicios web para construir una aplicacin haciendo bsquedas sobre USSI, interpretando documentos WSDL y construyendo peticiones SOAP (Figura 31). Todo
ello utilizando analizadores XML estndares. Pero para facilitar el proceso, se han implementado productos que ofrecen estas tecnologas de forma rpida y eficiente. Llamaremos a estos
productos plataformas de servicios web.
Generalmente una plataforma de servicios web est compuesta de herramientas de desarrollo, un servidor de ejecucin y un conjunto de servicios de gestin de la plataforma:
La herramientas de desarrollo se usan para crear los servicios web, generar las descripciones WSDL asociadas, y generar los proxies que permiten a los clientes usar los servicios.
El servidor de ejecucin de servicios procesa los mensajes SOAP y proporciona un contenedor para los servicios web. Para cada peticin, el procesador SOAP analiza el mensaje,
traduce los datos XML del mensaje al lenguaje nativo e invoca el servicio. Cuando el servicio termina su trabajo, el servidor traduce los resultados al formato XML, lo empaqueta
y lo enva en un mensaje de respuesta SOAP, que es enviado a la aplicacin cliente.
Las herramientas de gestin proporcionan un mecanismo para desplegar, arrancar, parar,
configurar y administrar el servicio web, entre otras posibles utilidades.
La plataforma de servicios web adems puede proporcionar o extender nuevas capacidades a
travs de las cabeceras SOAP, por ejemplo soporte de transacciones o fiabilidad en el reparto
89

Figura 31: Arquitectura de una plataforma de servicios web.

de mensajes SOAP. En la Figura 32 se muestra un diagrama con las posibles capacidades que
podra soportar la plataforma de servicios web.

11.6.

Servicios web [11.3. de Computacin Distribuida, M. L. Liu]

Los servicios web proporcionan servicios de red transportados por HTTP, y estn siendo propuestos como una nueva forma de construir aplicaciones de red desde componentes distribuidos
independientes del lenguaje y de la plataforma. Veremos uno de los protocolos (SOAP Simple
Object Access Protocol) y una API (API SOAP de Apache) como ejemplos de esta tecnologa.
Un servicio web se proporciona por un objeto servidor y se accede por un cliente. El servidor
y el cliente intercambian mensajes de acuerdo a protocolos estndares desarrollados para los
servicios web. La Figura 33 representa la jerarqua del protocolo. Lgicamente, el servidor y el
cliente intercambian mensajes en la capa de aplicacin. Fsicamente, se requiere de una serie de
protocolos para dar soporte al intercambio de mensajes.

Figura 33: Jerarqua de protocolos de servicios web.

La Figura 34 muestra los protocolos predominantes utilizados para servicios web. Aunque
todos son de inters, el resto de este captulo se centrar en el protocolo SOAP y sus aplicaciones.
La Figura 35 muestra la arquitectura software de un servicio web. El escuchador del servicio
en la mquina servidora recoge las peticiones de servicios transmitidas sobre la red. Cuando

90

Figura 32: Capacidades proporcionadas por la plataforma de servicios web.

Figura 34: Protocolos de servicios web.

recibe una peticin, se reenva al proxy del servicio. El proxy invoca a la lgica de aplicacin del
objeto servicio y transmite el valor devuelto al llamante.

Figura 35: Arquitectura software de servicios web.

11.7.

SOAP [11.4. de Computacin Distribuida, M. L. Liu]

SOAP es un protocolo que incorpora el paradigma de los objetos distribuidos y los protocolos
de Internet. Extiende HTTP para permitir acceso a objetos distribuidos que representan servicios
web.
Un cliente web manda una peticin HTTP, cuyo cuerpo contiene un mensaje con formato
SOAP que representa la llamada a un mtodo de un objeto de servicio. La peticin se transmite
a un servidor web, que la reenva, junto con los parmetros de la llamada, al mtodo. A conti-

91

nuacin se invoca el mtodo. Una vez completado, el valor devuelto por el mtodo se enva al
servidor web y a continuacin 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, como
se representa en la Figura 36.

Figura 36: Esquema de un mensaje de peticin SOAP.

Una peticin SOAP


La Figura 37 muestra la sintaxis de una peticin HTTP con una peticin SOAP. Describiremos
sus HTTP elementos en los siguientes prrafos.

Figura 37: Una peticin HTTP con una peticin SOAP.

Lneas de cabecera de la peticin HTTP El URI de la primera lnea debe especificar el objeto
al que se dirige la llamada a mtodo remoto. En el ejemplo es /ejemplos.
El Content Type debe especificarse como text/xml. El charset es una especificacin de la representacin de caracteres aceptada.
El Content Length, si est presente, debe ser la longitud en bytes del cuerpo de la peticin.

92

La lnea de cabecera SOAPAction especifica el objeto remoto al que se dirige la peticin. La


interpretacin de este elemento depende del programa. En la mayor parte de los casos, el URI y
el SOAPAction tendrn el mismo valor.
El cuerpo de la peticin

Hay dos partes en el cuerpo:

El recubrimiento SOAP se define con el elemento <SOAP-ENV:Envelope>. Tiene un conjunto de atributos requeridos que especifican el esquema de codificacin y el estilo del
recubrimiento.
El cuerpo de SOAP est definido con la etiqueta <SOAP-ENV:Body>, y contiene un solo
elemento, que representa la llamada al mtodo. Junto con el elemento se especifican el
nombre del mtodo (obtenerNombreEstado), el nombre de cada parmetro (numestados), el
valor de cada parmetro (41) y el tipo de datos de cada parmetro (int).
Tipos de datos SOAP tiene un rico conjunto de tipos de datos independientes del lenguaje, que
estn basados en los tipos de datos de los esquemas XML. La Tabla 11.1 resume un subconjunto
de 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

xsd:string

Cadena de caracteres

Hola Mundo

xsd:float o xsd:double

Nmero 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 tambin estn soportados en SOAP. Algunos de estos tipos
son:
Estructuras. Un valor puede ser una estructura, que se especifica con un elemento XML que
contiene subelementos. Las estructuras pueden estar anidadas y pueden contener cualquier
otro tipo de datos, incluyendo una matriz. Un ejemplo de una estructura de dos elementos
es:
<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 un
atributo SOAP-ENC:arrayType cuyos valores comienzan con ur-type[<nmero de elementos de
la 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 peticin/respuesta SOAP si el proveedor del servicio define y registra el tipo del objeto como un subtipo, y las dos partes proporcionan un
serializador y deserializador apropiado. A continuacin el nombre del subtipo se declara
como el atributo xsi:type del parmetro.

93

Una respuesta SOAP


El Listado 65 muestra una respuesta HTTP que contiene una respuesta SOAP existosa. Obsrvese que el content type es text/xml.
HTTP/1.1 200 OK
Connection: close
Content Length: 499
Content-Type: text/xml; charset=utf-8
Date: Wed, 28 Mar 2001 05:05:04 GMT
Server: 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 el


nombre del mtodo que ha sido llamado, con la palabra Response aadida al final del nombre
del mtodo (obtenerNombreEstadoResponse). El tipo de datos (string) y el valor (Dakota del Sur)
del valor devuelto est contenido en el subelemento Result.
Una llamada a mtodo SOAP puede fallar. Cuando esto sucede, la respuesta HTTP (Listado
66) contiene un cuerpo SOAP que define un cdigo y una cadena de error. El cdigo de error
(SOAP-ENV:Client) identifica el error, mientras que la cadena de error proporciona la descripcin
del mismo.
HTTP/1.1 500 Error
Connection: close
Content Length: 511
Content-Type: text/xml; charset=utf-8
Date: Wed, 28 Mar 2001 05:06:32 GMT
Server: 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
parmetros.</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Listado 66: Una respuesta HTTP que contiene una llamada a mtodo SOAP fallida.

Apache SOAP
Escribir cdigo para generar directamente la sintaxis XML para las peticiones y respuestas
SOAP puede ser tedioso y propenso a errores. Han aparcido numerosas API para SOAP para
facilitar la programacin que compete a las peticiones/respuestas SOAP, como Apache SOAP o
Apache AXIS (para Java).

94

La clase RPCMessage La clase RPCMessage de Apache SOAP encapsula una peticin SOAP. Un
objeto de esta clase contiene las siguientes instancias de campos: targetURI, methodName, params
y header, que representan los diferentes campos de una peticin SOAP.
La clase Call Es una subclase de la clase RPCMessage y representa una llamada a mtodo
remoto. Se puede crear un objeto de esta clase en un programa cliente SOAP, que puede llamar
al mtodo invoke para realizar la llamada a mtodo remoto.
La clase Parameter Un objeto de esta clase representa tanto parmetros como los valores devueltos por una llamada a mtodo. En el cliente se crea un objeto de esta clase por cada parmetro de mtodo remoto. En el servidor, se construye un objeto de esta clase para el valor
devuelto.
La clase Response Un objeto Response representa la respuesta de una llamada a mtodo. Tanto
el cliente como el servidor utilizan objetos Response para representar el resultado de una invocacin a mtodo. El servidor crea la respuesta, y el cliente extra informacin de la respuesta.
La clase Fault Un objeto Fault representa el contenido y la semntica del elemento <SOAPENV:Fault>, y lo devuelve al mtodo getFault ejecutado por el cliente. En el cdigo de ejemplo,
el mtodo getFaultString se invoca desde un cliente para recibir la descripcin del error que caus
el fallo de la llamada a mtodo.
Servicios web ya implementados
La idea de los servicios web es permitir a los desarrolladores de software hacer uso de
servicios ya implementados. Hay disponibles cierto nmero de servicios web para aquellos que
estn interesados en experimentar con la tecnologa [http://xmethods.net].
Invocacin de un servicio web utilizando Apache SOAP
El Listado 67 muestra el cdigo de ejemplo de un programa que invoca a un servicio SOAP.
Listado 67: Un ejemplo de cliente de servicio web.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import
import
import
import
import
import

java.io.*;
java.net.*;
java.util.*;
org.apache.soap.util.xml.*;
org.apache.soap.*;
org.apache.soap.rpc.*;

public class TempClient {


public static void main (String[] args) {
try {
URl url = new URL(http://services.xmethods.com:80/soap/servlet/rpcrouter);
String zipcode = "94320";
float temp = getTemp(url, zipcode);
System.out.println("La temperatura es " + temp);
} catch (Exception e) {
e.printStackTrace();
}
}
public static float getTemp(URL url, String zipcode) throws Exception {
Call call = new Call();
String encodingStyleURI = Constant.NS_URI_SOAP_ENC;
call.setEncodingSttyleURI(encodingStyleURI);
call.setTargetObjectURI("urn:xmethods-Temperature");
call.setMethodName("getTemp");
Parameter aParam = new Parameter("zipcode", String.class, zipcode, null);

95

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

Vector params = new Vector();


params.addElement(aParam);
call.setParams(params);
Response resp = call.invoce(url, "");
if(resp.generatedFault()) {
Fault f = resp.getFault();
System.err.println("Fault=" + f.getFaultCode() + ", " + f.getFaultString());
throw new Exception(f.getFaultString());
} else {
Parameter result = resp.getReturnValue();
Float readOut = (Float)result.getValue();
return readOut.floatValue();
}
}
}

Para prepararse para la invocacin de un mtodo proporcionado por el servicio web, se


instancia el objeto Call y se le asignan valores (lneas 22-28).
Para preparar los argumentos para la invocacin, se instancia un objeto de la clase Paramater
para cada parmetro. Cada objeto Parameter se inicializa con el nombre, el tipo de datos, el valor
y el estilo de codificacin del argumento (lnea 30).
La lista de parmetros se recoge en un vector (lneas 31-32) y a continuacin se asocia el
vector al objeto Call (lnea 33).
Para realizar la llamada a mtodo del servicio web, se especifica el mtodo invoke() del objeto
Call en el URL (lnea 35), donde url se refiere a un objeto de la clase Java URL, instanciado con
el servicio web URL (lnea 12).
Implementacin de un servicio web utilizando Apache SOAP
Un servicio web se define utilizando una interfaz Java, que contiene las declaraciones de
los mtodos proporcionados por el servicio. El listado 68 muestra la interfaz ITemp para un
servicio web de ejemplo, Temp, que proporciona el mtodo getTemp llamado por nuestro cliente
del Listado 67.
Listado 68: Una interfaz Java para un servicio web sencillo.
1
2
3
4
5
6
7
8

/**
* Ejemplo de interfaz de objeto de servicio SOAP.
*/
public interface ITemp {
float getTemp(String zipCode);
}

La interfaz se implementa como una clase de Java. El Listado 69 muestra una definicin de
ejemplo de la clase Temp, que implementa a ITemp.
Listado 69: Implementacin de un servicio web sencillo.
1
2
3
4
5
6
7
8

public class Temp implements ITemp {


public float getTemp(String zipCode) {
System.out.println("Temperatura para el cdigo postal " + zipCode + " solitada.
");
return 74.5F; // por simplicidad del ejemplo, devuelve constante
}
}

Un servicio SOAP necesita ser instalado y configurado en la mquina servidora, y este procedimiento depende de la implementacin.

96

Вам также может понравиться