Está en la página 1de 21

Prácticas de laboratorio

Un chat distribuido orientado a


objetos basado en RMI
(3 sesiones)

Concurrencia y
Sistemas Distribuidos

Introducción

El objetivo de esta práctica es introducir a los estudiantes a los sistemas distribuidos y al diseño
orientado a objetos de aplicaciones distribuidas. La aplicación seleccionada para aprender y practicar
los Sistemas Distribuidos es una aplicación chat distribuida. Aunque existen distintos standard y multitud
de aplicaciones chat en el mercado, nuestra aplicación chat propuesta no imita ninguna aplicación
concreta, ni sigue ningún standard en particular, primando la claridad y sencillez de su implementación.
En concreto, en esta práctica se desarrolla un Chat distribuido orientado a objetos basado en Java-RMI.
Por tanto, se empleará RMI como middleware distribuido subyacente, pero cualquier otro middleware
que soporte objetos distribuidos podría ser utilizado.

Una vez completada esta práctica, se habrá aprendido a:


• Identificar los distintos componentes que conforman una aplicación distribuida.
• Entender la función del servicio de nombres, que registra nombres simbólicos para servicios u
objetos remotos, y asocia a cada nombre la referencia al servicio/objeto. Este mecanismo permite
que los clientes localicen esos servicios u objetos registrados.
• Introducir el paradigma Cliente/servidor y utilizar dicho paradigma para diseñar e implementar
aplicaciones distribuidas.
• Analizar una aplicación distribuida completa.
• Aprender a compilar y ejecutar aplicaciones distribuidas sencillas.

La duración estimada de esta práctica es de tres semanas. Cada semana debe asistir a una sesión de
laboratorio donde podrá comentar con el profesorado de prácticas sus progresos y resolver las dudas
que le surjan. Tenga en cuenta que necesitará destinar algo de tiempo de su trabajo personal para
concluir la práctica. La propuesta para la organización en sesiones es la siguiente:
• Sesión 1.- actividades 1, 2 y 3.
• Sesión 2.- actividad 4 e iniciar la actividad 5.
• Sesión 3.- completar la actividad 5.
Esta practica está preparada para realizarla desde los sistemas DSIC-Linux de Polilabs.

Actividad 1

En esta primera actividad lanzaremos a ejecución las componentes que integran la aplicación de Chat
distribuido orientado a objetos basado en Java-RMI. En concreto, la aplicación consta de tres tipos de
componentes, que deben lanzarse en el mismo orden en que los presentamos:

1) Un servidor de nombres (NameServer), que escucha en un puerto determinado, a través del cual
recibe peticiones desde servidores (ChatServer en nuestro caso) para registrar objetos remotos
(es decir, para asociar un nombre lógico a una determinada referencia a objeto remoto); o bien
recibe peticiones desde clientes (ChatClient en nuestro caso) para obtener la referencia asociada
a un nombre lógico.
2) Al menos un servidor de chat (ChatServer), identificado mediante un nombre (por defecto
"TestServer"). Podemos lanzar varios servidores de chat y registrarlos en el mismo servidor de
nombres, si cada uno posee un nombre lógico único distinto.
3) La cantidad de clientes de chat (ChatClient) que se desee. Cada cliente se identifica mediante un
nombre o nick único y se conectará al servidor de chat que se le indique.

Instrucciones
1. Entre en DSIC-LINUX de Polilabs.
2. Al arrancar la sesión estaremos en una máquina denominada ldsic-vdiNN, donde NN son dos dígitos
que identifican la máquina virtual concreta. El DSIC dispone de 20 máquinas virtuales, que van
desde ldsic-vdi01 hasta ldsic-vdi20. Si abrimos un terminal (botón derecho del ratón
sobre el fondo de pantalla, opción 'Abrir en un terminal') tendremos un terminal similar al
de la siguiente figura, en cuyo prompt aparece:
o Nuestro usuario (ejemplo: esarvil@upvnet.upv.es)
o El nombre de la máquina (ej. ldsic-vdi01)
o El directorio actual (en este caso ~/Escritorio), donde ~ corresponde a nuestro
directorio inicial, al que también se llega al ejecutar la orden cd

3. En su unidad W, cree el directorio csd y descargue allí el fichero DistributedChatRMI.tgz


proporcionado para la práctica (disponible en el Lessons de la práctica 4 en el sitio PoliformaT de la
asignatura), descomprímalo y acceda al directorio recién creado. En concreto, realice:
$ cd $HOME/W
$ mkdir csd
$ cd csd
$ tar xvf DistributedChatRMI.tgz
$ cd DistributedChatRMI

2. En el directorio DistributedChatRMI verá que se encuentran los ficheros NameServer.java,


ChatServer.java y ChatClient.java correspondientes a la aplicación proporcionada en
esta práctica. Compile estos ficheros:
$ javac *java

CSD Actividades de laboratorio Java-RMI 2


Vamos a lanzar a continuación las diferentes componentes de nuestra aplicación (NameServer,
ChatServer y varios ChatClient). Para ello, lanzaremos cada componente en un terminal distinto
(en total, tendremos 4 terminales a la vez). Se recomienda redimensionar cada terminal y moverlos para
tener los 4 visibles de forma simultánea.

IMPORTANTE: asumimos que en todos los terminales estamos situados en el directorio en el que
tenemos el resultado de la compilación (donde están los ficheros .class).

3. En el primer terminal lance el servidor de nombres (NameServer), indicando el número de puerto


en donde se quedará escuchando peticiones que le lleguen. Para esta práctica utilizaremos el rango
de puertos 9000 - 9499. En un puerto (port) de una máquina únicamente puede escuchar un
componente. Por tanto, para componentes distintos habrá que utilizar puertos diferentes. Por
ejemplo, podemos lanzar el servicio de nombres en el puerto 9000, tal y como se muestra a
continuación:

Nota: a continuación se muestran los parámetros permitidos para la aplicación NameServer.

Estos parámetros indican: la máquina (host) donde se lanza el servidor de nombres (por defecto, asume
localhost, es decir, la máquina local); y el número de puerto (port) en el que escuchará el servidor de
nombres. Si no se indica número de puerto, NameServer utilizará por defecto el puerto 9000.

Nota: al lanzar el servidor de nombres, en el caso de que el puerto a utilizar ya esté ocupado, aparecerá
un mensaje "Port already in use", como se muestra en la siguiente figura.

Esto significa que ya se ha lanzado un servidor escuchando en ese puerto de esa máquina virtual, por
ejemplo, si ya hemos lanzado un componente que usa ese mismo puerto o bien lo ha hecho otro alumno
que esté usando la misma máquina virtual. Para solucionar este problema, reintente la orden java
NameServer con otro número de puerto, dentro del rango indicado para la práctica.

4. En el segundo terminal lance el servidor de chat, con la orden siguiente (asumiendo que el servidor
de nombres se ha lanzado previamente en el puerto 9000 en la máquina local):
$ java ChatServer nsport=9000 serverName="TestServer"

Nota: a continuación se muestran los parámetros permitidos para la aplicación ChatServer

CSD Actividades de laboratorio Java-RMI 3


Estos parámetros indican1: la máquina (nshost) donde se ha lanzado el servidor de nombres (por
defecto, asume localhost, es decir, la máquina local); el número de puerto (nsport) en el que escucha el
servidor de nombres (por defecto, asume el puerto 9000); y el nombre (serverName) a asignar al servidor
de chat (por defecto "TestServer").

Por ejemplo, podemos lanzar el servidor de chat (asumiendo que previamente hemos lanzado el
servidor de nombres en el puerto 9000 y en nuestra máquina local, en este caso ldsic-vdi01), tal y
como se muestra a continuación:

Si todo va bien, aparecerá un mensaje indicando que el servidor ("TestServer" en este caso) está activo,
escuchando en el primer puerto libre que ha encontrado a partir del puerto 9000 (en el ejemplo, está
escuchando en el puerto 9001), y que ha creado determinados canales (en este caso, los canales #Spain,
#Linux y #Friends).

Importante: En el caso de que no se haya lanzado previamente el servidor de nombres, o bien se haya
lanzado en un host y/o puerto diferentes al indicado en la llamada a ChatServer, aparecerá un error en
la conexión, similar a la siguiente figura. Deberá repetir los pasos 3 y 4 conforme corresponda.

5. En el tercer y cuarto terminal lance sendos clientes de chat, con la orden siguiente (asumiendo que
el servidor de nombres se ha lanzado previamente en el puerto 9000 en la máquina local, y que
ChatServer se ha registrado con el nombre por defecto "TestServer"):
$ java ChatClient nsport=9000 serverName="TestServer"

Nota: A continuación se muestran los parámetros permitidos para la aplicación ChatClient

1
El parámetro host no se utilizará en el desarrollo de esta práctica en las máquinas del laboratorio DSIC-Linux.
Ese parámetro permite que, en el caso de utilizar una máquina que tenga más de una IP, se especifique la IP
concreta a registrar en la referencia.

CSD Actividades de laboratorio Java-RMI 4


Estos parámetros indican: la máquina (nshost) donde se ha lanzado el servidor de nombres (por defecto,
asume localhost); el número de puerto (nsport) en el que escucha el servidor de nombres (por defecto,
asume el puerto 9000); el nombre lógico (serverName) por el que preguntará al servidor de nombres
para obtener la referencia de objeto asociada (por defecto, "TestServer"); el host o dirección propia (por
defecto, localhost); el nick o nombre de usuario con el que se conectará; y el canal (channel) al que
unirse de forma automática cuando se lance la aplicación. Todos estos parámetros son opcionales.

Por ejemplo, podemos lanzar el servidor de chat (asumiendo que previamente hemos lanzado el
servidor de nombres en el puerto 9000 y en nuestra máquina local, en este caso ldsic-vdi01), tal y
como se muestra a continuación:

Aparecerá un mensaje indicando que ChatClient está activo en el primer puerto libre que ha encontrado
a partir del puerto 9000 (en el ejemplo, está activo en el puerto 9002). El cliente es el único componente
que presenta un interfaz gráfico, cuyo funcionamiento se explica en el siguiente apartado. Los posibles
mensajes de error (por ejemplo, si no es capaz de contactar con el servidor de nombres) aparecen en
dicho interfaz.

Nota: Se pueden lanzar tantos clientes como se desee, pero recomendamos un mínimo de tres clientes
para comprobar que funciona de forma correcta la aplicación de chat, de forma que dos clientes hablen
entre sí dentro del mismo canal (y se difunde la información entre ellos) y un tercer cliente está unido a
un canal diferente (y no recibe los mensajes de los otros canales). Para cada nuevo cliente se abriría otro
terminal y se lanzaría el componente ChatClient allí.

Comprobación

Si todo ha funcionado de forma correcta, por cada ChatClient lanzado se mostrará una interfaz gráfica
similar a la de la siguiente imagen.

CSD Actividades de laboratorio Java-RMI 5


Al asignar un nombre en "My nick" al usuario y darle al botón Connect, se conectará al servicio de chat
proporcionado por el servidor (en este caso, llamado "TestServer"), mostrándonos la lista de canales.
La siguiente figura corresponde al cliente del usuario Harry tras conectarse al servidor de chat TestServer
y unirse al canal #Linux. Aparece un botón Disconnect para abandonar el chat, así como un botón Leave
para abandonar el canal.

Nota: el nick del usuario debe ser único. Si se propone un nick que ya está es uso, el servidor genera el
correspondiente mensaje de error (java.rmi.RemoteException: User exists).

Una vez establecida la conexión, el servidor responde con la lista actual de canales, que se muestra en
la columna izquierda. Los canales se denominan #xxx, y el cliente puede unirse a un canal de la lista
mediante un doble click sobre el nombre deseado (o bien pinchando el botón Join). Cuando un usuario
se une a un canal, aparece la lista de usuarios suscritos a ese canal en la columna de la derecha (en la
figura anterior, Harry es el primer usuario en suscribirse al canal #Linux).

El área de texto de la parte inferior permite escribir un mensaje, que puede dirigirse a:
- Un usuario concreto, si hemos seleccionado previamente el nombre de un usuario de la columna
derecha. En ese caso se trata de un mensaje privado. En el texto "Chatting area" aparecerá el
nombre del usuario seleccionado.
- Un canal, si hemos seleccionado previamente el nombre de un canal de la columna izquierda. En ese
caso se trata de un mensaje público, puesto que se difunde a todos los usuarios suscritos a dicho
canal. En el texto "Chatting area" aparecerá el nombre del canal seleccionado.

El área central es la zona de mensajes (no editable). En la parte superior de dicha área central, se
muestran los mensajes públicos y privados que nos hacen llegar otros usuarios. En la parte inferior del
área central, se muestran los mensajes que nos llegan del propio ChatServer (ej. mensaje de conexión
al servidor, mensaje de entrada a un canal, mensaje de salida de un canal), así como cualquier mensaje
de error que aparezca durante la ejecución .

Tras lanzar varios clientes (cada uno desde un terminal distinto, pero todos desde su máquina local),
compruebe el funcionamiento correcto del chat:
• En el terminal donde ha lanzado el servidor de nombres, deberá aparecer:
o Un mensaje de tipo "rebind" que indica que el ChatServer se ha registrado en el servidor
de nombres, mostrándose su nombre lógico y la referencia (endpoint) asociada. En
nuestro ejemplo:
==> rebind (TestServer, {IChatServer, endpoint:[ldsic-vdi01.upvnet.upv.es:9001]})

o Varios mensajes de tipo "resolve", uno por cada ChatClient que se haya lanzado. Este
mensaje resolve indica que se ha solicitado al servidor de nombres que nos proporcione

CSD Actividades de laboratorio Java-RMI 6


la referencia asociada a un nombre lógico (TestServer en nuestro caso). En nuestro
ejemplo:
==> resolve (TestServer) --> {IChatServer, endpoint:[ldsic-vdi01.upvnet.upv.es:9001]})

• En el terminal del servidor ChatServer, se mostrará un mensaje de tipo User 'Harry'


connected, por cada usuario que se conecte a la aplicación chat, así como un mensaje de tipo
User 'Harry' disconnected por cada usuario que se desconecte.

• En el terminal de cada cliente ChatClient se mostrará un mensaje que indica el puerto que está
usando dicho cliente. Por ejemplo:
OK ==> 'ChatClient' running at ldsic-vdi01.upvnet.upv.es:9002
Compruebe que a cada cliente se le ha asignado un número de puerto distinto.

• Usando la interfaz gráfica de cada cliente, pruebe a enviar tanto mensajes al canal (ej. tras
doble-click sobre el canal #Linux, se muestra "Chatting area #Linux"), como mensajes privados
a otro usuario (ej. tras doble-click sobre el usuario Sally, se muestra "Chatting area Sally").
Pruebe también a unirse (Join) y salir (Leave) de los canales. Fíjese en todos los mensajes que se
muestran en la parte inferior del "Chatting area".

Pruebas de uso de la aplicación


Una vez comprobada la funcionalidad básica, se proponen distintas variantes:

1º) Verifique el funcionamiento de los canales. Para ello, compruebe que al seleccionar un canal se
actualiza de forma correcta el conjunto de clientes conectados a dicho canal.

2º) Lance más de un servidor chat, dándole a cada uno un nombre distinto. Por ejemplo, puede incluir
su nombre de usuario (ej. "TestServer-esarvil").
$java ChatServer nsport=9000 serverName="TestServer-esarvil"
Compruebe que en el terminal del servidor de nombres se muestra un nuevo mensaje de tipo "rebind"
asociado con este servidor de chat lanzado.

3º) Compruebe el funcionamiento de sus otros servidores de chat, lanzando clientes adicionales que
se conecten a ellos. Por ejemplo:
$java ChatClient nsport=9000 serverName="TestServer-esarvil"

Compruebe que en el terminal del servidor de nombres se muestra un nuevo mensaje de tipo "resolve"
asociado con este cliente de chat lanzado. Y observe que en la interfaz gráfica nos estaremos conectando
a este nuevo servidor.

4º) Compruebe la difusión de los mensajes públicos (enviados al canal). Verifique que cada servidor
posee su propio conjunto de canales, aunque el nombre de los canales pueda coincidir. Vea también
que el alta/baja de usuarios se difunde a todos los usuarios del chat correspondiente, pero no afecta al
resto de servidores.

CSD Actividades de laboratorio Java-RMI 7


Cuestiones
a) Un usuario que se conecta a un canal, ¿recibe la conversación previa desarrollada en dicho canal?
b) ¿Son los mensajes persistentes?
c) ¿Cuántos componentes ha lanzado? ¿Cuántos puertos se han utilizado? ¿Hay componentes que
compartan el mismo número de puerto?
d) ¿Qué significan exactamente los mensajes de tipo "rebind" y "resolve" que aparecen en el terminal
del servidor de nombres? Indique cuántos mensajes de cada tipo le han aparecido y qué
representan.

Actividad 2

En la actividad anterior se han desplegado todos los componentes de la aplicación en la misma máquina,
por comodidad y facilidad para el despliegue. En esta segunda actividad comprobaremos que los
componentes de nuestra aplicación pueden residir en cualquier máquina. Para ello, desplegaremos los
distintos componentes en máquinas virtuales diferentes.

Para lanzar desde nuestra máquina órdenes sobre otra máquina distinta utilizaremos el comado ssh
(secure Shell), que permite un acceso seguro a otra máquina, de forma que toda la información
transferida está cifrada.

En esta actividad lanzaremos cada componente de la aplicación en una máquina distinta y


comprobaremos que la aplicación funciona correctamente, con independencia de la ubicación física de
los distintos componentes. En concreto, veremos que se difunde el alta y baja de los usuarios y se
entregan correctamente tanto los mensajes públicos como los privados.

Instrucciones

En la descripción de las instrucciones que siguen, se asume que estamos conectados inicialmente a la
máquina ldsic-vdi01; que lanzaremos el servidor de nombres en la máquina ldsic-vdi11 y
puerto 9000; el servidor ChatServer, con nombre lógico "TestServer-esarvil" en la máquina ldsic-
vdi12; un cliente ChatClient en la máquina ldsic-vdi13; y otro cliente ChatClient en la máquina
ldsic-vdi14. La siguiente tabla muestra la descripción de las máquinas y puertos en las que se ha
lanzado cada componente de la aplicación en el ejemplo descrito en estas instrucciones.

Componente Ejecutándose en Puerto Orden utilizada para lanzar a ejecución el componente


máquina
NameServer ldsic-vdi11 9000 java NameServer port=9000
ChatServer (TestServer- ldsic-vdi12 9001 java ChatServer nsHost="ldsic-vdi11"
nsPort=9000 serverName="TestServer-esarvil"
esarvil)
ChatClient ldsic-vdi13 9001 java ChatClient nsHost="ldsic-vdi11"
nsPort=9000 serverName="TestServer-esarvil"
nick="Alice"
ChatClient ldsic-vdi14 9001 java ChatServer nsHost="ldsic-vdi11"
nsPort=9000 serverName="TestServer-esarvil"
nick="Bob"

Cada alumno deberá realizar las modificaciones oportunas a las instrucciones indicadas, para adecuarse
a su máquina inicial de conexión y a las máquinas donde desee lanzar los distintos componentes. Para
facilitar la tarea, el alumno deberá completar la Tabla 1 para detallar claramente en qué máquina y
puerto reside cada componente de la aplicación.

CSD Actividades de laboratorio Java-RMI 8


Al igual que en la aplicación anterior, lanzaremos cada componente en un terminal distinto (en total,
tendremos 4 terminales a la vez). Se recomienda redimensionar cada terminal y moverlos para tener los
4 visibles de forma simultánea. En cada terminal, deberemos conectarnos a una máquina distinta (vía
ssh) y colocarnos en el directorio donde tenemos los ejecutables de nuestra aplicación (ej. directorio
W/csd/DistributedChatRMI), tal y como se muestra en el paso 1.

1. Desde el primer terminal (asumimos que inicialmente estamos conectados a ldsic-vdi01),


conéctese a otra máquina virtual (por ejemplo, a ldsic-vdi11). Acepte la solicitud ( Are you
sure you want to continue connecting? yes) y escriba su contraseña de usuario. Una
vez conectado, sitúese en el directorio DistributedChatRMI y lance a ejecución el servidor de
nombres (NameServer). Si el puerto a utilizar ya estuviera ocupado, indique otro número de
puerto dentro del rango 9000 - 9499. En este ejemplo se ha usado el puerto 9000.

$ssh -X ldsic-vdi11
$cd W/csd/DistributeChatRMI
$java NameServer port=9000

2. Desde el segundo terminal, conéctese a otra máquina virtual (por ejemplo, a ldsic-vdi12).
Acepte la solicitud (yes) y escriba su contraseña de usuario. Una vez conectado, sitúese en el
directorio DistributedChatRMI y lance a ejecución el servidor de chat (ChatServer). Debe
indicar el nombre de la máquina y número de puerto en el que ha lanzado previamente su servidor
de nombres. Además, deberá indicar un nombre lógico para ChatServer, preferiblemente que
incluya como sufijo su nombre de usuario. En este ejemplo, se ha utilizado "TestServer-esarvil" como
nombre lógico.

$ssh -X ldsic-vdi12
$cd W/csd/DistributeChatRMI
$java ChatServer nsHost="ldsic-vdi11" nsport=9000
serverName="TestServer-esarvil"

CSD Actividades de laboratorio Java-RMI 9


3. Desde el tercer terminal, conéctese a otra máquina virtual (por ejemplo, a ldsic-vdi13), sitúese
en el directorio DistributedChatRMI y lance a ejecución un primer cliente de chat
(ChatClient). Debe indicar el nombre de la máquina y número de puerto en el que ha lanzado
previamente su servidor de nombres, así como el nombre lógico con el que ha registrado a
ChatServer (ej. "TestServer-esarvil"). Puede indicar también un nick para el cliente (ej. Alice).
Cuando aparezca la interfaz gráfica, pulse el botón Connect para proceder a la conexión a la
aplicación de chat.
$ssh -X ldsic-vdi13
$cd W/csd/DistributeChatRMI
$java ChatClient nsHost="ldsic-vdi11" nsPort=9000
serverName="TestServer-esarvil" nick="Alice"

4. Desde el cuarto terminal, conéctese a otra máquina virtual (por ejemplo, a ldsic-vdi14), y lance
a ejecución un segundo cliente de chat (ChatClient), de forma similar al paso anterior. Use un
nick diferente para este cliente (ej. Bob). Cuando aparezca la interfaz gráfica, pulse el botón Connect
para proceder a la conexión a la aplicación de chat.
$ssh -X ldsic-vdi14
$cd W/csd/DistributeChatRMI
$java ChatClient nsHost="ldsic-vdi11" nsport=9000
serverName="TestServer-esarvil" nick="Bob"

CSD Actividades de laboratorio Java-RMI 10


Para facilitarle la tarea, en cada paso de las instrucciones complete la línea de la tabla correspondiente
al terminal indicado, según su caso:

Terminal Componente Ejecutándose en Puerto Orden utilizada para lanzar a


máquina ejecución el componente
1º NameServer ldsic-vdi

2º ChatServer: ldsic-vdi
TestServer-
3º ChatClient ldsic-vdi

4º ChatClient ldsic-vdi

Tabla 1. A completar por el alumno.

Comprobación
Si todo ha funcionado correctamente, tras lanzar cada componente desde una máquina virtual distinta,
tendremos lo siguiente:
• En el terminal donde se ha lanzado el servidor de nombres, deberá aparecer, al menos, un
mensaje de tipo "rebind" asociado a nuestro ChatServer y varios mensajes de tipo "resolve"
asociados a nuestros clientes. Compruebe que las direcciones y números de puerto que se
indican coinciden con los anotados en la tabla que ha rellenado previamente.
• En el terminal del servidor ChatServer, deberá aparecer un mensaje de tipo "User XXX
connected" por cada usuario conectado a nuestra aplicación. Compruebe que los usuarios
conectados coinciden con los anotados en su tabla.
• Usando la interfaz gráfica de cada cliente, compruebe que los clientes pueden entrar y salir de
los canales, así como enviarse entre sí tanto mensajes al canal como mensajes privados.

Actividad 3

Una vez comprobado el despliegue de componentes en distintas máquinas, se proponen diferentes


escenarios:
1. Lance el ChatServer y los clientes en local, utilizando el NameServer que haya lanzado su
profesor de prácticas. Para ello, se requiere que el profesor informe previamente del nombre
de la máquina virtual y número de puerto en el que ha lanzado su NameServer. De este modo,
todos los alumnos de la clase se conectarán al mismo NameServer. Se recomienda añadir el login
de cada alumno como sufijo del nombre lógico de ChatServer (ej. "TestServer-esarvil", siendo
esarvil un login de alumno), para poder registrar el servidor de chat de forma adecuada en el
servidor de nombres, sin que interfiera con el de otros alumnos.

CSD Actividades de laboratorio Java-RMI 11


2. Utilice ahora el NameServer lanzado por otro alumno y lance sus propios ChatServer y clientes
para utilizar la aplicación de chat. En este caso únicamente se exige a los ChatServer que tengan
un nombre único distinto entre los conectados al mismo servidor de nombres.
3. Finalmente, lance los clientes en local, utilizando los ChatServers de otros alumnos, de forma
que se compruebe que se siguen difundiendo correctamente los mensajes a clientes remotos.
El NameServer a utilizar puede ser el del profesor, o bien el del otro alumno del paso anterior.

Actividad 4

En esta actividad analizaremos el diseño de la aplicación de chat distribuido que se ha proporcionado en


esta práctica, para así comprender su funcionamiento interno. Dicho conocimiento servirá de base para
la actividad 5.

En el código fuente proporcionado encontramos:


- Los ficheros java que corresponden a los componentes utilizados en las actividades anteriores
(NameServer, ChatServer, ChatClient), así como el fichero ChatRobot.java, que se utilizará en la
actividad 5.
- Un conjunto de carpetas que agrupan distintos ficheros, según su funcionalidad:
o Faces: contiene los interfaces remotos (i.e. definen el interfaz de los objetos accesibles de
forma remota). Por tanto, describen la interacción entre los objetos fundamentales de la
aplicación:
§ IChatChannel: interfaz que ofrece un canal del chat. Un canal mantiene el
conjunto de usuarios conectados, lo cual permite la difusión de mensajes.
§ IChatMessage: interfaz que ofrece un mensaje de chat.
§ IChatServer: interfaz que ofrece un ChatServer.
§ IChatUser: interfaz que ofrece un usuario del chat (por ejemplo para que se le
notifiquen mensajes).
§ INameServer: interfaz que ofrece un servidor de nombres a sus clientes.
§ MessageListener: interfaz NO remoto que define el comportamiento de un
cliente para ‘escuchar’ mensajes.
o Impl: contiene las clases java que implementan los anteriores interfaces remotos.
§ ChatChannelImpl: implementa IChatChannel
§ ChatMessageImpl: implementa IChatMessage
§ ChatServerImpl: implementa IChatServer
§ ChatUserImpl: implementa IChatUser
§ NameServerImpl: implementa INameServer
o Lib: biblioteca externa que se puede utilizar para mejorar el aspecto del interfaz gráfico.
o Ui: contiene el código requerido para implementar la interfaz gráfica de un cliente.
o Utils: contiene clases de utilidades que facilitan la implementación de la aplicación.
o Utils_rmi: contiene clases de utilidades para simplificar la configuración de los
componentes, permitiendo, por ejemplo, la definición de los argumentos que reciben y sus
valores por defecto.

Para comprender el funcionamiento de la aplicación es imprescindible analizar los interfaces de la


carpeta Faces, así como el código de ChatServer y ChatClient. Las clases que implementan esos
interfaces (contenidas en la carpeta Impl) pueden resultar de interés para consultar aspectos muy
concretos. El resto del código (carpetas lib, ui, utils y utils.rmi) no es necesario para entender el
funcionamiento del chat. La siguiente figura resume lo básico de estas interfaces y clases:

CSD Actividades de laboratorio Java-RMI 12


Interface - Métodos Clases que lo implementan
IChatChannel IChatUser[] join(IChatUser) ChatChannelImpl Mantiene nombre del canal (name) y
void leave(IChatUser)
String getName()
conjunto de usuarios del canal (users).
void sendMessage(IChatMessage) Permite añadir (join) /eliminar (leave)
usuarios del canal.
Implementa difusión de mensajes
(sendMessage) en el canal, iterando
sobre users.
IChatMessage IChatUser getSender() ChatMessageImpl Mantiene emisor, destino y texto del
Remote getDestination()
String getText()
mensaje.
Boolean isPrivate() Indica si el mensaje es privado.
IChatServer IChatChannel createChannel(String) ChatServerImpl Permite crear un canal.
IChatChannels[] listChannels()
IChatChannel getChannel(String)
Mantiene la lista de canales (channels)
IChatUser getUser(String) y de usuarios (users).
boolean connectUser(IChatUser) Devuelve un canal o un usuario a partir
boolean disconnectUser(IChatUser)
del nombre.
Permite conectar un usuario a la
aplicación de chat o desconectarlo.
IChatUser String getNick() ChatUserImpl Representa al usuario. Mantiene su
void sendMessage(IchatMessage)
nick.
Permite enviar un mensaje al usuario
INameServer InameServer getNameServer(String,int) NameServerImpl Permite localizar fácilmente el
void bind(String, Remote)
void rebind(String, Remote)
NameServer. Mantiene pares
void unbind(String) (nombre, referencia_Remota).
Remote lookup(String) Permite añadir nuevas entradas (bind,
rebind), eliminar entradas (unbind), y
buscar por nombre (lookup)
MessageListener void messageArrived(IchatMessage) ChatClient Permite la recepción de mensajes.
ChatRobot

El siguiente esquema muestra una disposición básica del chat distribuido. En este caso, hay un servidor
de nombres (NameServer), un ChatServer y dos ChatClient (que corresponden a los usuarios Alice y Bob).
Estos 4 procesos conforman un sistema sencillo que, sin embargo, es más complejo e interesante que
un esquema de cliente/servidor puro.

NameServer

CSD Actividades de laboratorio Java-RMI 13


El esquema muestra los pasos ordenados que nuestra aplicación sigue cuando los usuarios Alice y Bob
se unen a un canal de chat denominado “#Friends” y empiezan a chatear. Alice envía un mensaje “Hola”
y ambos usuarios lo reciben al estar conectados al canal.

A continuación se detallan los pasos seguidos. Cada paso está marcado con un círculo rojo numerado en
el esquema:
1. ChatServer registra su objeto principal "ChatServerImpl" en el servidor de nombres, con su
nombre lógico (por defecto "TestServer").
2. Los dos ChatClients buscan el objeto "ChatServerImpl" utilizando el servidor de nombres y
obtienen su proxy IChatServer. Nótese que los tres procesos tienen que estar de acuerdo en
el nombre lógico del objeto “ChatServerImpl”, que en este ejemplo es "TestServer".
3. Los clientes del Chat se conectan al ChatServer. Para ello crean un objeto ChatUserImpl local
y lo registran en el servidor, mediante el método connectUser de IChatServer.
4. Los clientes del Chat preguntan la lista de canales, mediante el método listChannels de
IChatServer.
5. Los clientes del Chat se unen al canal “#Friends”. Para ello obtienen primero el proxy
IChatChannel del canal solicitado (mediante el método getChannel de IChatServer) y se unen
a dicho canal, usando el método join de IChatChannel.
Nótese que el primer usuario en unirse al canal también recibe una notificación cuando el
segundo cliente se une. Esta notificación de canal no se ha dibujado en el esquema.
6. Alice envía un mensaje de chat sencillo al canal, utilizando el método sendMessage de
IChatChannel.
7. A partir de dicho envío, el canal retransmite el mensaje a todos los usuarios conectados (al
canal). Para ello, ChatChannelImpl invoca al método sendMessage de IChatUser de cada
usuario del canal para retransmitir los mensajes.
8. Los usuarios, cuando reciben el mensaje, analizan su contenido usando el método
messageArrived. 8a representa una invocación local, mientras que 8b es una invocación
remota.

Nótese que, aunque el rol de los ChatClient consiste principalmente en actuar como clientes de chat,
también actúan como servidores, pues tienen objetos (ChatUserImpl) que son invocados de forma
remota. ChatChannelImpl invoca a métodos de IChatUser para retransmitir los mensajes, de los cuales
se envía sus referencias (no el contenido del mensaje). Cualquiera que necesite ver el contenido de un
mensaje dado tiene que invocar métodos sobre la referencia del mensaje. Este patrón de invocación de
objetos no es habitual en la mayoría de entornos de chat pero es lo bastante completo para comprender
las aplicaciones orientadas a objetos distribuidas.

Cuestiones

a) ¿En qué orden deben arrancarse los distintos componentes (NameServer, ChatServer, ChatClient)?
b) ¿Cómo localiza un ChatClient al ChatServer a partir de su nombre?
c) Asumiendo que un ChatClient conoce la ubicación del NameServer (nshost, nsport) y el nombre del
ChatServer (serverName), indique qué secuencia de métodos invoca ChatClient para obtener la lista
de canales.
d) Observe que tanto IChatChannel como IChatUser definen el método void sendMessage(IChatMessage).
¿Qué diferencia hay entre ambas implementaciones?
e) ¿Qué objetos remotos define ChatServer?
f) Indique si un ChatClient crea algún objeto remoto y si los registra en el servidor de nombres.

CSD Actividades de laboratorio Java-RMI 14


Actividad 5

En esta actividad se completará el contenido de la clase ChatRobot, para así implementar un "bot" de
nuestra aplicación chat. Este ChatRobot será un proceso que:
• Reciba argumentos en línea de órdenes: nshost, nsport, serverName, channelName, nick
o nshost y nsport se utilizan para localizar el NameServer.
o channelName indica a qué canal debe conectarse.
o nick indica el nick o nombre que tendrá el ChatRobot como usuario del chat.
• Una vez lanzado no necesitará más interacción con el usuario que lance dicho programa. Así,
diferencia de un ChatClient, el ChatRobot no posee interfaz gráfico y tampoco permite
interacción a través de la consola. La única acción externa posible es detener su ejecución
mediante Ctrl-C.
• Deberá conectarse al servidor y canal indicados usando el nick proporcionado, y monitorizar
todos los mensajes de entrada que le lleguen:
o Si se trata del aviso de que un nuevo cliente X se ha conectado a ese canal, el ChatRobot
debe enviar un mensaje público de saludo "Hola X" a través del canal.
o Si se trata de un mensaje privado procedente de un ChatClient, deberá contestarle con
otro mensaje privado donde indique "Soy el robot ‘Nick’, y la única respuesta que he
aprendido hasta ahora es que 1+1 = 2 ".

Para la implementación de este proceso, se dispone del esqueleto de la clase ChatRobot, donde
únicamente aparece la declaración de la clase y su método main. La siguiente tabla desglosa esta
actividad en una serie de pasos que permitirán completar la funcionalidad de forma progresiva. Cada
paso:
• Describe de la funcionalidad deseada en dicho paso.
• Detalla las instrucciones para conseguirlo.
• Detalla el mecanismo para validar dicha funcionalidad.
• Plantea cuestiones que ayudan a completar las instrucciones o entender las decisiones de diseño
que se toman en cada paso.

El ChatRobot presenta ciertas similitudes con ChatClient, por lo que se puede consultar el código de
ChatClient como referencia para facilitar la resolución de los distintos pasos.

Paso Descripción Instrucciones Comprobación


1 Obtener referencia Obtener host y port del NameServer Imprimir la referencia con
al NameServer desde línea de órdenes RemoteUtils.remote2String
Obtener la referencia con
INameServer.getNameServer
2 Obtener la Obtener el nombre del ChatServer a Imprimir la referencia con
referencia al partir del objeto conf. RemoteUtils.remote2String
ChatServer Obtener la referencia con la
operación lookup del objeto
INameServer
3 Conectarse al Obtener el nick a partir de conf. Lanzar excepción en caso de error.
ChatServer Crear un objeto ChatUserImpl Si no hay excepciones, mostrar
para representar al robot. mensaje en pantalla indicando que
Registrarlo en el servidor usando el se ha conectado.
método connectUser del
ChatServer

CSD Actividades de laboratorio Java-RMI 15


4 Obtener la lista de Utilizar el método listChannels Imprimir la lista de canales.
canales del ChatServer para obtener la lista. Mostrar por pantalla el canal de
Comprobar que el canal conf y el resultado de la
channelName indicado en conf búsqueda.
está en la lista.
5 Unirse al canal Obtener el canal con el método Lanzar un par de ChatClient
getChannel del ChatServer. (digamos A y B) conectados al canal
Usar join y obtener la lista de en el que luego lanzaremos el
usuarios. robot. El robot debe mostrar la
lista de usuarios (debe aparecer el
nick del robot, A y B).
Comprobar que la lista coincide
con la mostrada por A y B.
6 Enviar mensaje Construir mensaje con Comprobar que los clientes
público ChatMessageImpl. conectados al canal lo reciben.
Enviar el mensaje sobre el canal.
7 Enviar mensaje Construir mensaje con Comprobar que el cliente destino
privado ChatMessageImpl. lo recibe (seleccionando al ROBOT
Enviar el mensaje sobre el cliente en su lista de usuarios).
destino.
8 Recibir y mostrar Garantizar que ChatRobot Lanzar mensajes desde clientes y
mensajes implementa MessageListener. mostrar los detalles de cada
Obtener emisor, destino y texto del mensaje en pantalla.
mensaje.
Determinar si es privado,
procedente del servidor, o público.
9 Responder Responder de forma adecuada a los Verificar comportamiento según la
adecuadamente a mensajes JOIN. especificación.
los mensajes Responder de forma adecuada a los
mensajes privados.

A continuación, se detallan con más profundidad los pasos e instrucciones que debe realizar en el
código de ChatRobot.

Paso 5.1.- Obtener referencia al NameServer


El robot debe recoger desde línea de órdenes los argumentos nshost, nsport, serverName,
channelName, y nick. Para ello se utiliza la clase ChatConfiguration.
Una vez conocido el valor de nshost y nsport, deben utilizarse para acceder al NameServer, como paso
previo para localizar al ChatServer.

Instrucciones:
1. Obtener host y port del NameServer a partir de la línea de órdenes. Observe cómo resuelve
ChatClient ese mismo aspecto usando una variable conf de tipo ChatConfiguration.
2. Obtener la referencia al NameServer con INameServer.getNameServer. Para entender
mejor cómo realizar este paso, puede analizar también el código de ChatClient y ver cómo se ha
resuelto allí.

CSD Actividades de laboratorio Java-RMI 16


Comprobación:
§ Imprima la referencia obtenida. El método remote2String de la clase RemoteUtils (en el
directorio rmi-utils) permite transformar cualquier referencia remota en un String, que podemos
mostrar en pantalla. Resulta interesante comprobar la información asociada a la referencia.

Cuestiones:
a) ¿Qué hace el objeto conf en ChatClient? ¿cómo se inicializa? ¿Cuáles son sus valores por defecto?
b) ¿Qué indica el texto que se ha impreso de la referencia?

Paso 5.2.- Obtener la referencia al ChatServer


Cuando arranca el ChatServer, crea un objeto remoto y lo registra en el NameServer bajo un nombre X
determinado. El robot recibe en el argumento serverName el nombre del ChatServer con el que debe
contactar (supongamos que es X). Para obtener acceso al objeto remoto correspondiente, el robot debe
preguntar al NameServer por el objeto remoto llamado X. Este procedimiento es similar al realizado por
ChatClient.

Instrucciones:
1. Obtenga el nombre del ChatServer proporcionado en el argumento serverName al lanzar a
ejecución ChatRobot desde línea de órdenes.
2. Obtenga la referencia al ChatServer con la operación lookup de INameServer.
3. La referencia obtenida debe guardarse en una variable de tipo IChatServer. Deben tratarse las
posibles excepciones (ej. no encuentra el servidor de nombres, no encuentra el objeto, etc.)

Comprobación:
§ Imprima el mensaje indicando la posible excepción, o si todo ha ido bien el valor de la referencia
obtenida (usando remote2String).

Cuestiones:
a) ¿Qué pasa si no hemos indicado el nombre del servidor como argumento?
b) ¿Qué ocurre si el nombre buscado no existe?
c) ¿Por qué no necesitamos conocer el host y port donde está ChatServer?

Paso 5.3.- Conectarse al ChatServer


Una vez que el robot tiene acceso al servidor, necesita conectarse al mismo. De esta forma, ChatServer
puede:
• Validar el nick proporcionado (el nick de cada usuario del chat debe ser único y no puede estar
vacío)
• Obtener una referencia al IChatUser correspondiente: cada usuario del chat implementa un
objeto remoto y le pasa la referencia al ChatServer, de forma que el ChatServer puede invocar
determinadas operaciones sobre cada usuario registrado.

Para registrarse, ChatRobot debe invocar el método connectUser de IChatServer, pasando como
argumento un objeto de tipo ChatUser (que contiene el nick del robot).

Instrucciones:
1. Cree un objeto ChatUserImpl para representar al robot (con el nick indicado en línea de
órdenes).
2. Registre ese objeto en el servidor usando el método connectUser de IChatServer.

CSD Actividades de laboratorio Java-RMI 17


Comprobación:
§ Verifique posibles excepciones (ej. no se encuentra el servidor, el nick está vacío, etc.), y si no
hay excepciones muestre un mensaje indicado que se ha conectado con éxito.
§ Lance NameServer, un ChatServer y un cliente. Conecte el cliente a un canal. Lance ahora su
ChatRobot sobre ese mismo canal, y observe si dicha conexión afecta al cliente.

Cuestiones:
a) ¿Qué pasa si el nick ya lo está usando otro usuario del chat?
b) En el código de ChatClient se usa this como segundo argumento del constructor ChatUserImpl.
¿Puede hacer lo mismo el robot?
c) Al lanzar el ChatRobot, ¿qué podemos observar en el interfaz cliente? ¿Por qué?

Paso 5.4.- Obtener la lista de canales


Un usuario puede conectarse a cualquier canal (y posteriormente desconectarse). ChatServerImpl
implementa el método listChannels, que devuelve la lista de canales disponibles. Se debería
obtener esa información antes de intentar conectarse a un canal. En concreto:
• ChatClient necesita la lista de canales para mostrarlos en pantalla y permitir al usuario elegir el
canal deseado.
• ChatRobot recibe el canal al que conectarse como argumento (channelName), pero debería
verificar que el valor de dicho argumento aparece en la lista de canales.

Instrucciones:
1. Obtenga la lista de canales usando el método listChannels de IChatServer.
2. Compruebe que el canal proporcionado como argumento en la línea de órdenes (i.e.
channelName) aparece también en la lista de canales.

Comprobación:
§ Imprima la lista de canales.
§ Muestre el valor de channelName (argumento de la línea de órdenes) y el resultado de la
búsqueda en la lista de canales.

Cuestiones:
a) ¿Cómo se obtienen los nombres de los canales a partir de lo que devuelve el método
listChannels de IChatServer?

Paso 5.5.- Unirse al canal


Para unirse a un canal hay que obtener previamente la referencia al canal correspondiente (con el
método getChannel de IChatServer) e invocar el método join sobre dicha referencia. Al conectarse
a un canal se obtiene la lista de usuarios del mismo, que incluirá al propio usuario que ha pedido unirse
al canal.

Instrucciones:
1. Obtenga el canal con el método getChannel de IChatServer.
2. Utilice el método join sobre el canal y obtenga la lista de usuarios. Muestre dicha lista en
pantalla.

CSD Actividades de laboratorio Java-RMI 18


Comprobación:
§ Lance uno o varios clientes ChatClient y únalos un canal determinado. Debe mantener estos
clientes activos para el resto de pasos siguientes.
§ Lance su ChatRobot sobre ese mismo canal. En la lista de usuarios que muestre el robot,
deberán aparecer como usuarios tanto los nicks de los clientes lanzados como el del robot.
Además, en la interfaz de cada cliente deberá aparecer el nick del robot en la lista de usuarios.

Cuestiones:
a) Cuando un cliente se une al canal, el canal avisa al resto de usuarios del canal. ¿Qué método se
utiliza para ello?

Paso 5.6.- Enviar mensaje público


En este paso se añadirá al ChatRobot las instrucciones necesarias para que el robot envíe mensajes al
canal en el que está conectado. Para ello, el robot construirá un objeto de tipo ChatMessageImpl y lo
enviará al canal, y el canal se encargará de la difusión del mensaje al resto de usuarios conectados al
canal. Cuando un cliente recibe el mensaje, lo muestra en su interfaz gráfica.

Instrucciones:
1. Construya un mensaje utilizando la clase ChatMessageImpl. El contenido del mensaje puede
ser simplemente del estilo "Hola a todos".
2. Envíe el mensaje sobre el canal, utilizando el método sendMessage.
Comprobación:
§ Lance su ChatRobot sobre el canal en el que están previamente conectados varios usuarios.
§ Compruebe que el mensaje de saludo de su robot es recibido por todos ellos (i.e. aparece en la
interfaz gráfica de cada usuario conectado a ese canal).
Cuestiones:
a) ¿Qué hace el canal para difundir el mensaje a los usuarios de ese canal?

Paso 5.7.- Enviar mensaje privado


En el paso anterior se lanzaban mensajes públicos (mensajes al canal). Pero también se pueden enviar
mensajes privados, es decir, directamente a otro usuario. En este caso, el ChatRobot seleccionará, de la
lista de usuarios que ha recibido del canal en el que está conectado, al primer usuario de la lista (que no
sea el propio robot) y le enviará un mensaje privado del estilo "Hola, soy un bot".

Instrucciones:
1. Construya un mensaje utilizando la clase ChatMessageImpl. El contenido del mensaje puede
ser simplemente del estilo "Hola, soy un bot".
2. Recorra la lista de usuarios y envíe al primer usuario de la lista dicho mensaje (que no sea el
propio robot), utilizando el método sendMessage sobre su IChatUser correspondiente.

Comprobación:
§ Lance su ChatRobot sobre el canal en el que están previamente conectados varios usuarios.
§ Compruebe que el mensaje de saludo "Hola, soy un bot" de su robot llega únicamente al usuario
indicado, y no al resto de usuarios del canal.

Cuestiones:
a) ¿Cómo interviene el canal en el envío de un mensaje privado?
b) ¿Cómo se sabe si un mensaje es privado o público? ¿Se utiliza el mismo constructor de mensajes
para mensajes públicos (al canal) y privados?

CSD Actividades de laboratorio Java-RMI 19


Paso 5.8.- Recibir y mostrar mensajes
Para poder recibir mensajes, debe implementarse el interfaz MessageListener. Dicho interfaz
consta de un único método, void messageArrived(IchatMessage), cuyo código debe implementarse en las
clases que hagan uso de este interfaz, tal y como se ha realizado en la clase ChatClient. Por tanto, en la
clase ChatRobot se deberá completar el método messageArrived para así garantizar que ChatRobot
implementa de forma adecuada el interfaz MessageListener.

El código del método messageArrived debe descomponer el mensaje, obteniendo su emisor,


destino y texto concreto. Para ello, se hará uso de los métodos proporcionados por el interfaz
IChatMessage, que permiten obtener las distintas componentes del mensaje (i.e. emisor, destino,
texto), así como determinar si el mensaje es privado, si procede del servidor, o bien es un mensaje
público (i.e. enviado al canal).

Instrucciones:
1. Compruebe que ChatRobot implementa la interfaz MessageListener.
2. En el método messageArrived, obtenga el emisor, destino y texto del mensaje.
3. En dicho método, determine si el mensaje es privado, procedente del servidor, o público.
4. Muestre toda esta información por pantalla.

Comprobación:
§ Lance su ChatRobot sobre el canal en el que están previamente conectados varios usuarios.
§ Lance mensajes desde varios clientes (tanto mensajes al canal como mensajes privados al robot)
y compruebe que el robot muestra en su terminal asociada los detalles de cada mensaje que ha
recibido.
§ Haga que algunos clientes salgan del canal y se unan al canal. Compruebe que el robot muestra
en su terminal asociada los detalles de los mensajes de conexión y desconexión que recibe por
parte del servidor.

Cuestiones:
a) En la recepción de un mensaje, ¿cómo diferenciamos si se trata de un mensaje público o privado?
b) ¿Cómo podemos saber si un mensaje lo ha enviado el propio servidor?
c) ¿Qué diferencia hay respecto al componente destino entre un mensaje público y un mensaje
privado?
d) ¿Dónde se invoca el método messageArrived?

Paso 5.9.- Responder adecuadamente a los mensajes


La especificación del robot indica que debe responder a dos tipos de mensajes (y por tanto ignorar el
resto):
• Mensajes correspondientes al alta de un usuario. Se trata de mensajes públicos procedentes del
servidor y cuyo texto empieza por “JOIN”. La respuesta debe ser un mensaje público saludando
al nuevo usuario, tal y como se realizaba en el paso 5.6
• Mensajes privados. La respuesta debe ser otro mensaje privado, tal y como se realizaba en el
paso 5.7.

Instrucciones:
1. Escriba en el método messageArrived de ChatRobot el código necesario para clasificar los
tipos de mensajes (privado/público, enviado por el servidor o no, JOIN o de otro tipo).
2. Para el caso de un mensaje JOIN, escriba el código necesario para obtener el nick del nuevo
usuario. Construya un mensaje con contenido "Hola 'nick'" y envíelo a través del canal.

CSD Actividades de laboratorio Java-RMI 20


3. Para el caso de un mensaje privado enviado por un usuario, construya un mensaje con contenido
"Soy un robot, y la única respuesta que he aprendido hasta ahora es que 1+1 = 2" y envíelo al
ChatUser de dicho usuario.

Comprobación:
§ Lance el robot y conéctelo a un canal. Luego lance cliente(s) y observe el resultado en el terminal
del robot y en la interfaz del resto de clientes.
§ Desde uno de los clientes, envíe un mensaje privado al robot y observe la respuesta obtenida.

Cuestiones:
a) Explique qué objetos y operaciones se invocan cuando un cliente se conecta al canal #Friends,
asumiendo que el ChatRobot ya está conectado a ese canal.
b) Asumiendo que NameServer se lanza en la máquina A y ChatServer se lanza en la máquina B, y que
lanzamos ChatRobot en la máquina C y ChatClient en la máquina D, y que todos conocen los datos
del servidor de nombres (nsport y nshost), indique para cada objeto ChatServerImpl,
ChatChannelImpl, ChatUserImpl, ChatMessageImpl, ChatClient, ChatRobot:
o en qué máquina está cada uno.
o si se usa una única instancia o varias de cada objeto.
o cómo pueden comunicarse las instancias entre sí (cómo se obtienen sus referencias, y si las
invocaciones son locales o remotas).

CSD Actividades de laboratorio Java-RMI 21

También podría gustarte