Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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.
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
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).
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"
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"
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.
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.
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
• 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".
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.
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.
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.
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.
$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"
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"
2º ChatServer: ldsic-vdi
TestServer-
3º ChatClient ldsic-vdi
4º ChatClient ldsic-vdi
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
Actividad 4
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
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.
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.
A continuación, se detallan con más profundidad los pasos e instrucciones que debe realizar en el
código de ChatRobot.
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í.
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?
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?
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.
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é?
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?
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.
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?
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?
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?
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?
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.
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).