Chat en Java

Anuncio
Laboratorio de Fundamentos de Sistemas Distribuidos
Chat en Java - 1
Tipo de entrega:
por grupos de prácticas
Fecha límite:
sesiones de laboratorio
Lugar:
Atenea (nou campus)
Objetivos del proyecto:
• Crear y utilizar objetos
• Crear y utilizar variables y métodos de clases
• Utilizar try, catch y finally para detectar y manejar excepciones
• Implementar clientes y servidores en Java que se comuniquen entre sí utilizando
sockets
• Implementar un servidor con subprocesamiento múltiple
Resultados a entregar:
• Los resultados esperados de esta práctica es la carpeta del Workspace del Eclipse
que contiene los códigos de las aplicaciones. Coloca los códigos de cada sesión en un
package llamado Chat_X
Descripción de la aplicación
En este proyecto vamos a desarrollar una aplicación distribuida con arquitectura
cliente/servidor. La aplicación distribuida es un Chat que permite a los clientes darse de alta y
de baja en el Chat, enviar mensajes a todos los clientes en línea y pedir la lista de clientes en
línea.
El código del cliente se programará en la clase ClienteChat (ClienteChat.java) y el
código del servidor en las clases ServidorChat (ServidorChat.java) y Cliente
(Cliente.java)
Estudio Previo
1. Estudio de los apartados (“Sockets, Clients, and Servers”, y “Programming
Examples”) de la sección 10.4 (“Networking”) del libro “Introduction to Programming
Using Java Version 4.0, July 2002” de David J. Eck (en el apartado comentarios
tienes cómo acceder on-line al contenido del libro)
2. Compila, ejecuta y analiza detenidamente el ejemplo DateServer.java y
DateClient.java. Esta aplicación utiliza un objeto de la clase PrintWriter para escribir
datos en un socket y un objeto de la clase Reader para leer datos de un socket.
Nota:
Para compilar DateServer.java y DateClient.java necesitas la clase TextIO.class que
es una clase que no pertenece al SDK.
Coloca el código fuente de TextIO.java en el mismo package que el código
DateServer.java y DateClient.java para que puedas usar la clase TextIO.
La clase TextIO sólo se usa como clase de soporte (no es necesario que la entiendas
para realizar la práctica)
3. Prueba a NO arrancar el servidor de la aplicación DateServer.java y DateClient.java y
arranca el cliente. Analiza la secuencia de sentencias que se ejecutan cuando
ejecutas el cliente (tráelo a la sesión de laboratorio en papel)
4. Compila, ejecuta y analiza detenidamente el ejemplo CLChatClient.java y
CLChatServer.java. Esta aplicación utiliza un objeto de la clase PrintWriter para
1
escribir datos en un socket y un objeto de la clase TextReader para leer datos de un
socket.
Nota:
Para compilar estos ejemplos sucede lo mismo que en los ejemplos del apartado
anterior (aquí necesitas la clase TextReader.class)
Coloca el código fuente de TextReader.java en el mismo package que el código de
CLChatClient.java y CLChatServer.java para que puedas compilar los ejemplos.
En el apartado comentarios tienes donde hay una explicación de esta clase y de sus
métodos.
5. Prueba a arrancar el servidor de la aplicación CLChatClient.java y CLChatServer.java
y NO arranques el cliente de la aplicación. Analiza la secuencia de sentencias que se
ejecutan en el servidor (tráelo a la sesión de laboratorio en papel)
6. Analiza el protocolo que utiliza el servidor de nuestro chat formado por las clases
ServidorChat.java y Cliente.java. Si programamos el cliente en una clase
ClienteChat.java, ¿Qué deberá enviar ClienteChat por el socket para registrarse?
(tráelo a la sesión de laboratorio en papel)
Comentarios
Introduction to Programming Using Java Version 4.0, July 2002
El libro “Introduction to Programming Using Java Version 4.0, July 2002” de David J. Eck
([email protected]) está accessible on-line desde http://www.faqs.org/docs/javap/index.html
El
código
fuente
de
las
aplicaciones
http://www.faqs.org/docs/javap/source/index.html
lo
puedes
bajar
de
También puedes bajarte el manual y los ejemplos en un archivo comprimido para “Windows”,
“Linux/UNIX and MacOS X” y “Linux/UNIX” ( apartado “Downloading Links” ) o sólo el manual
en un archivo pdf.
Clase TextReader
Se describe la clase y cómo usarla en la sección 10.1 (“Streams, Readers, and Writers”) del
manual Introduction to Programming Using Java Version 4.0, July 2002.
Cómo debugar en el Eclipse
Tienes un ejemplo gráfico de cómo hacerlo en la ayuda del Eclipse (abre el Help del Eclipse y
busca el tema “Debugging your programs”)
Streams, Readers and Writers
Puedes consultar información de estas clases en las secciones 10.1 (“Streams, Readers, and
Writers”), 10.2 (“Files”) y 10.3 (“Programming with Files”) del manual Introduction to
Programming Using Java Version 4.0, July 2002.
Sockets
En Java la programación de aplicaciones que se comunican en
Internet a través del protocolo TCP (Transmisión Control
Protocol) se realiza desde la capa de aplicación, sin necesidad de
interactuar con la capa de transporte. Para ello se utilizan las
clases Socket y ServerSocket, que proporcionan
comunicación en red independiente de la plataforma.
2
Un socket es un punto final de una comunicación bidireccional entre 2 programas
ejecutándose en la red. Un socket se asocia a un número de puerto de forma que el
protocolo de la capa de transporte (en nuestro caso TCP) pueda identificar la aplicación a la
que están destinados los datos. Así, los sockets permiten crear la ilusión al programador de
que mandar/recibir datos por la red es algo similar a escribir/leer datos de un disco.
El servidor corre sobre una máquina y tiene un socket asociado a un puerto determinado, por
el que está esperando la petición de una conexión de un cliente.
El cliente conoce el nombre de la máquina donde se está ejecutando el servidor y el número
de puerto por el que está escuchando el servidor.
El cliente realiza una petición de
conexión al servidor con el nombre de
máquina del servidor y el puerto.
Si no se produce ningún error el
servidor acepta la conexión. Crea un
nuevo socket para atender la petición
de ese cliente y mantiene el socket
original que está escuchando para
atender peticiones de nuevos clientes.
A partir de este momento el cliente y el servidor pueden comunicarse leyendo o escribiendo
en sus sockets.
La clase Socket implementa un lado de la conexión bidireccional entre dos aplicaciones Java
en la red. Permite crear conexiones de clientes con servidores. La clase ServerSocket
implementa el otro lado de la conexión bidireccional. En concreto permite crear un socket que
puede escuchar en un puerto y aceptar conexiones de clientes.
Ambas son implementaciones que ocultan los detalles de las plataformas concretas (hardware
y sistema operativo) donde se ejecutan las aplicaciones cliente y servidor.
Sesión de laboratorio
Ejercicio 1: sockets
Escribe un programa cliente llamado ClienteChat.java que se conecte y desconecte del
servidor formado por las clases ServidorChat.java y Cliente.java que te damos.
El cliente debe realizar esta secuencia:
1.
2.
3.
4.
pedir el nick al usuario del Chat
registrarse en el servidor (enviando el comando REGISTER y el nick)
pedir al usuario un comando y ejecutar el comando
Si el comando es CLOSE finalizar la aplicación. En caso contrario volver a 3.-
De momento los comandos que soporta nuestra aplicación son conectarse al servidor y
desconectarse. Si el usuario introduce cualquier otro comando distinto se printará un mensaje
por pantalla informativo en la consola de ClienteChat y se pedirá al usuario que introduzca un
nuevo comando.
Utiliza a clase BufferedReader para leer de un socket. Utiliza la clase PrintWriter para escribir
en un socket. Utiliza la clase JOptionPane para introducir el nick del usuario y para leer los
comandos que introduce el usuario.
3
Chat en Java - 2
Estudio Previo
1. Estudio de los apartados (“ArrrayLists ”, y “Vectors”) de la sección 8.3 (“Dynamic
Arrays, ArrayLists, and Vectors”) del libro “Introduction to Programming Using Java
Version 4.0, July 2002” de David J. Eck (en el apartado comentarios tienes cómo
acceder on-line al contenido del libro)
2. Estudio del apartado (“The Special Variables this and super”) de la sección 5.5 (“this
and super”) del libro “Introduction to Programming Using Java Version 4.0, July
2002” de David J. Eck (en el apartado comentarios tienes cómo acceder on-line al
contenido del libro)
3. Programa una clase llamada MyClass (en un archivo MyClass.java) que tenga un
método llamado myMethod. El método myMethod imprime por pantalla el mensaje
“Soy un método de la clase MyElement”.
Programa una clase llamada CheckAL (en un archivo CheckAL.java) que almacene en
un objeto de la clase ArrayList objetos de la clase MyClass, recorra el ArrayList y
ejecute para cada elemento el método myMethod programado en la clase MyClass.
(tráelo a la sesión de laboratorio en papel)
Comentarios
Introduction to Programming Using Java Version 4.0, July 2002
El libro “Introduction to Programming Using Java Version 4.0, July 2002” de David J. Eck
([email protected]) está accessible on-line desde http://www.faqs.org/docs/javap/index.html
El
código
fuente
de
las
aplicaciones
http://www.faqs.org/docs/javap/source/index.html
lo
puedes
bajar
de
También puedes bajarte el manual y los ejemplos en un archivo comprimido para “Windows”,
“Linux/UNIX and MacOS X” y “Linux/UNIX” (apartado “Downloading Links” ) o sólo el manual
en un archivo pdf.
La clase Vector
La clase Vector permite almacenar un array dinámico de objetos e ir añadiendo objetos o
eliminándolos, así como llamar a otros métodos que se necesitan cuando trabajas con
cualquier conjunto de objetos
Analiza este fragmento de código que crea un Vector de objetos, añade un objeto de la clase
Client al Vector y llama al atributo name de cada objeto Client que hay en el vector, sin
necesidad de conocer cuantos clientes hay en el vector (método size() de la clase Vector):
import java.util.* ;
Vector clients = new Vector();
Client cl =new Client();
clients.addElement(cl);
for (int i=0; i<clients.size();i++){
((Client)(clients.elementAt(i))).name;
}
clients.removeElement(cl);
clients.toString();
Es importante hacer notar varios aspectos en el código:
4
•
La sentencia import java.util.*; permite utilizar todo lo que contiene el package
java.util de Java y la clase Vector se encuentra en ese package(similar al include de
C)
•
El método addElement() introduce un elemento en el Vector
•
El método removeElement() elimina un elemento del Vector
•
El método size() de la clase Vector permite conocer el número de objetos que
contiene el objeto Vector sobre el que se aplica (clients).
•
El método element.At(i) devuelve una referencia que apunta al objeto que hay en la
posición i del objeto Vector sobre el que se aplica (en nuestro caso apunta un objeto
Client).
•
Como los elementos de un Vector pertenecen por defecto a la clase padre más
genérica (Object) para acceder al atributo name de la clase Cliente hay que forzar la
conversión del tipo (como en C)
((Client)(clients.elementAt(i))).name;
Sesión de laboratorio
Ejercicio 2: La clase Vector
En este ejercicio vamos a añadir a nuestro servidor la funcionalidad de almacenar la
información de los clientes que están conectados en el servidor y vamos a añadir a nuestra
aplicación un nuevo comando (comando SEND_CLIENT_LIST) que permite a un usuario del
chat saber los nicks de los usuarios registrados en el servidor.
Vector clientList
Cada vez que un usuario se conecta (comando REGISTER), se añade un objeto de la
clase Cliente en el Vector clientList.
Cada vez que un usuario se desconecta (comando CLOSE), se elimina el objeto que
representa a ese usuario del Vector clientList.
Comando SEND_CLIENT_LIST
El comando lo declaramos como una constante llamada SEND_CLIENT_LIST de tipo char
que contiene el carácter ‘:’
El cliente envía SEND_CLIENT_LIST (‘:’) al servidor y recibe una línea por cada usuario
registrado en el servidor “< + el atributo name de ese cliente” más una línea
con “>” que indica fin de comando SEND_CLIENT_LIST (‘:’). Por ejemplo, si el servidor
tuviera dos clientes registrados “Pablo” y “Toñi”, se recibiría:
>Pablo
>Toñi
<
Los caracteres ‘>’ y ‘<’ los declaramos como constantes de tipo char llamadas
CLIENT_INFO y END_CLIENT_INFO .
5
a) Modifica el código de nuestra aplicación añadiendo el Vector clientList en la parte de
servidor (se declara e inicializa en ServidorChat y se pasa por parámetro cuando se crea un
objeto Cliente), actualizando el Vector clientList cada vez que un usuario se conecte
(comando REGISTER) o se desconecte (comando CLOSE) y programando el nuevo
comando en nuestro Chat (tanto en la parte de cliente como en la parte de servidor)
En la parte de ClienteChat crea un nuevo Vector cada vez que se pida un
SEND_CLIENT_LIST al servidor y almacena en él los nicks de los usuarios que vas
recibiendo. Cuando recibas fin del comando SEND_CLIENT_LIST (<) printa por pantalla la
lista de usuarios que tienes en el vector
Como nuestro Chat sólo atiende a un ClienteChat (es secuencial), sólo permite un ClienteChat
conectado al Chat no podemos probar que SEND_CLIENT_LIST devuelva más de un name.
Nota: Existen varias formas de compartir la lista de usuarios. Una es utilizando el comando
‘static’ y otra es pasando una referencia del objeto ‘clientList’. Cualquiera de las dos formas
es valida.
Chat en Java - 3
Estudio Previo
1. Estudio del tutorial “Threads (Scheme)” de javaHispano.
2. Programa una clase llamada MyThread (en un archivo MyThread.java) que sume
enteros de 1 a 10.000 y una clase llamada Prueba (en un archivo Prueba.java) que
cree un thread y lo ponga en marcha (tráelo a la sesión de laboratorio en papel)
Comentarios
javaHispano
El web javaHispano (http://www.javahispano.org) mantiene noticias, manuales, tutoriales de
Java en castellano.
El manual de esta parte de la práctica se encuentra en la sección Java / Tutoriales / J2SE
(http://www.javahispano.org/tutorials.type.action?type=j2se) bajo el nombre “Threads
(Scheme)”
Threads
Los threads o hilos de ejecución son segmentos de código de un programa que se ejecutan
secuencialmente de modo independiente de otras partes del programa. Un proceso puede
estar constituido por uno o más threads. Un
thread esta compuesto por: una CPU virtual, el
código que ejecuta el procesador y los datos
sobre los que trabaja el código. Dos threads
comparten código si ejecutan código de objetos
que pertenecen a la misma clase
acceso a un objeto común.
Los datos pueden ser o no compartidos por
diferentes threads. Eso ocurre cuando tienen
6
Los threads se utilizan para aislar y coordinar tareas. Sin el uso de threads hay aplicaciones
que son casi imposibles de programar:
•
Las que tienen tiempos de espera importantes entre etapas
•
Las que consumen muchos recursos de CPU e impiden que el procesador atienda
simultáneamente otros eventos o peticiones del usuario (por ejemplo, un chat)
Java soporta la ejecución paralela de varios threads. Los threads en una misma máquina
virtual comparten recursos (por ejemplo memoria). Los threads en varias máquinas virtuales
necesitan mecanismos de comunicación para compartir información. Hay dos modos de
conseguir threads en Java:
•
Extender la clase Thread,
•
Implementando la interface Runnable.
Creación extendiendo la clase Thread.
El nuevo thread se crea extendiendo la clase Thread y redefiniendo el método run().
public class ClienteThread extends Thread {
// Atributos y métodos de la clase . . .
public void run() {
// código propio del thread
}
}
public class Test {
public static void main(String[] args){
while (true) {
socketClient = listener.accept();
ClienteThread c =new ClienteThread(socketClient);
c.start();
}
}
}
Creación implementando la interface Runnable.
El constructor de la clase Thread recibe un argumento que debe ser una instancia de una
clase que implementa la interface Runnable, implementando el método run().
public class ClienteThread implements Runnable {
// Atributos y métodos de la clase . . .
public void run(){
// código propio del thread
}
}
public class Test{
public static void main(String args[]){
ClienteThread r = new ClienteThread();
Thread t = new Thread(r);
t.start();
}
}
7
Sesión de laboratorio
Ejercicio 3: Threads-1
En este ejercicio vamos a añadir a nuestro servidor la funcionalidad de atender a varios
clientes al mismo tiempo (concurrentemente). Así podremos comprobar que los comandos
REGISTER y CLOSE, programados anteriormente, funcionan tal y como se esperaba.
También podremos añadir más comandos a nuestro Chat.
Tal como funciona nuestra aplicación en este momento para cada ClienteChat que se
conecta a ServidorChat se crea un objeto de la clase Cliente donde se almacena su nick
(name) y el socket asignado en tiempo de ejecución en la máquina servidor para comunicarse
con la máquina cliente (ClienteChat.java), etc.
a) Modifica el código de ServidorChat.java y de Cliente.java de forma que se cree
un thread para cada ClienteChat.java que se conecte a ServidorChat.java.
Nota: Si dentro del método run() de un thread utilizas métodos que generan
excepciones, es necesario poner ese código dentro de un bloque try/catch
b) Comprueba que los comandos REGISTER y CLOSE, programados anteriormente,
funcionan tal y como se esperaba.
Chat en Java – 4
Estudio Previo
3. Estudio del ejemplo de uso de Threads “Ejemplo.java” (que te facilitamos junto
con el código y que también puedes encontrar en la documentación de Wikipedia).
4. Modifica el ejemplo para que muestre por pantalla el nombre del thread que se está
ejecutando.
5. Ejecuta el nuevo ejemplo varias veces, analízalo y describe cuándo cada uno de los
threads ejecutan código, si aunque no printen por pantalla tienen asignada la CPU,
qué printa por pantalla cada thread y si ambos threads finalizan cuando se ejecuta la
sentencia System.exit(0) (tráelo a la sesión de laboratorio en papel)
Nota: Si es necesario repasa el tutorial “Threads (Scheme)” de javaHispano.
Comentarios
javaHispano
El web javaHispano (http://www.javahispano.org) mantiene noticias, manuales, tutoriales de
Java en castellano.
El manual de esta parte de la práctica se encuentra en la sección Java / Tutoriales / J2SE
(http://www.javahispano.org/tutorials.type.action?type=j2se) bajo el nombre “Threads
(Scheme)”
Sesión de laboratorio
Ejercicio 4: Threads-2
En este ejercicio vamos a añadir a nuestro chat que la parte de cliente sea capaz de leer del
socket y de leer de teclado concurrentemente (en un chat en cualquier momento alguien
8
puede enviarte un mensaje mientras estás escribiendo tú un nuevo mensaje o pudiendo un
nuevo comando al servidor).
a) Basándote en el código de Ejemplo.java modifica el código de ClienteChat.java,
para que en el main se cree un objeto ClienteChat, se creen dos threads de ese objeto, uno
de los threads ejecute el método sendCommand() y el otro thread el método
listenServer().
El método sendCommand() tendrá el código del ClienteChat.java del ejercicio 3 que se
encarga de leer comando del usuario y enviarlo a la parte Servidor de nuestra aplicación
El método listenServer() leerá continuamente lo que le envía el servidor
(Cliente.java) y cuando el servidor envíe el mensaje de despedida (“Bye Bye …”) cerrará
el socket y la aplicación de ClienteChat.java.
Chat en Java – 5
Estudio Previo
1. Estudio de la clase String de la sección “4.2. Strings and Characters” del libro “Java in
a Nutshell, 4th Edition” de David Flanagan (en el apartado comentarios tienes cómo
acceder on-line al contenido del libro).
Nota: No es necesario para realizar la práctica estudiar ninguno de los
subapartados 4.2.X.
2. Estudio
a.
b.
c.
d.
los siguientes métodos de la clase String:
int indexOf(int ch)
boolean startsWith(String prefix)
String substring(int beginIndex)
String substring(int beginIndex, int endIndex)
Nota: Tienes un ejemplo de código de la sección “4.2. Strings and Characters”
del libro “Java in a Nutshell, 4th Edition” de David Flanagan. También puedes
utilizar la “Documentación en línea de las clases del SDK versión 1.4” (en el
apartado comentarios tienes cómo acceder on-line)
Comentarios
Java in a Nutshell, 4th Edition
El
libro
“Java
in
a
Nutshell,
4th
(http://proquest.safaribooksonline.com/0596002831)
biblioteca de la UPC (http://bibliotecnica.upc.edu/).
Edition”
de
está accesible
David
on-line
Flanagan
desde la
Puedes consultar el libro tanto desde un PC conectado a la red de la UPC como desde fuera
de la UPC (en este caso debes configurar tu navegador tal y como explica el link “Accés
remot” http://bibliotecnica.upc.es/remot/)
Documentación en línea de las clases del SDK versión 1.4
API del SDK http://java.sun.com/j2se/1.4/docs/api/index.html)
9
Sesión de laboratorio
Ejercicio 5: La clase String
En este ejercicio vamos a añadir a nuestro chat nuevos comandos. Los comandos son los
siguientes:
mensaje
Este comando envía un mensaje a todos los usuarios conectados en este momento al
chat. El mensaje no debe empezar ni por el carácter del comando SEND_CLIENT_LIST
(‘:’), ni por el REGISTER (‘[’), ni por el CLOSE (‘]’), ni por el PRIVADO (‘/’, reservado
para un futuro comando) Este mensaje aparece en cada una de las pantallas de los
usuarios conectados y la pantalla del usuario conectado muestra:
nickOrigen: mensaje
/nickDestino mensaje
Este comando envía un mensaje privado al usuario cuyo nick equivale al nickDestino
especificado en el comando. Este mensaje únicamente aparece en la pantalla del usuario
que envía el mensaje y la pantalla del usuario destinatario muestra:
Privado de nickOrigen a nickDestino: mensaje
a) Modifica el código de ServidorChat.java, Cliente.java y de ClienteChat.java
para que soporte estos nuevos comandos.
Ejercicio 6: Mejorando la aplicación
En este ejercicio se trata de mejorar la aplicación del chat que tenemos con algún o algunos
detalles que se te ocurran. Por ejemplo: que no se permita a un usuario registrarse con un
nick de un cliente ya registrado, añadir un nuevo comando, añadir interficie gráfica a nuestra
aplicación, etc…
10
Descargar