Академический Документы
Профессиональный Документы
Культура Документы
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
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
11
11
11
11
11
12
12
13
13
13
14
14
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
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
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
72
72
72
73
73
73
73
74
75
75
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
83
83
84
85
88
89
90
91
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1.
1.1.
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.
1.3.
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.
1.5.
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
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.*
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.
1.6.
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
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
1.7.
10
2.
2.1.
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.
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
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
2.7.
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.
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.
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.
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.
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
15
3.
3.1.
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.
3.2.
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.
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
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.
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.
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
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.
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
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.
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.
Mtodo/Constructor
Descripcin
DatagramSocket()
Mtodo/Constructor
Descripcin
DatagramSocket(int puerto)
void close()
void receive(DatagramPacket p)
void send(DatagramPacket p)
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
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 disconnect()
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
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.
Mtodo/Constructor
Descripcin
ServerSocket(int puerto)
Mtodo/Constructor
Descripcin
SocketException
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
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
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
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.*;
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
4.5.
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.
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
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.
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.
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
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
/**
* 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
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
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
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
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
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
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.*;
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
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
5.4.
43
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
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
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
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
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
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.
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
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.
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
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
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
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.
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.
52
7.3.
7.4.
7.5.
53
7.6.
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.
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.
7.7.
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
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
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.
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;
}
/**
* 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;
}
}
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
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.
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
7.11.
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
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.
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
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;
}
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;
}
}
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
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
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
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
67
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.
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
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
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
71
10.
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.
10.2.
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.
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.
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.
73
10.7.
74
10.8.
Adaptadores de objetos
10.9.
IDL de Java
75
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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();
}
}
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
49
50
51
52
53
54
55
56
57
58
59
60
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
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
82
11.
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?
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.
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.
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
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.
86
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.
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.
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.
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.
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
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.
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.
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
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.
11.7.
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.
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
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.
Tipo
Ejemplo
xsd:int
-12
xsd:boolean
Valor booleano: 1 0
xsd:string
Cadena de caracteres
Hola Mundo
xsd:float o xsd:double
-12,214
xsd:timeInstant
Fecha/Hora
2001-03-27T00:00:01-08:00
SOAP-ENC: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
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.*;
95
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 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
Un servicio SOAP necesita ser instalado y configurado en la mquina servidora, y este procedimiento depende de la implementacin.
96