Sei sulla pagina 1di 11

Practica 5: Implementacion en Java de sistemas

cliente/servidor basados en comunicacion


sncrona
Programacion de Sistemas Concurrentes y Distribuidos
Grado de Ingeniera Informatica
Dpto. de Informatica e Ingeniera de Sistemas,
Escuela de Ingeniera y Arquitectura
Universidad de Zaragoza

1.

Objetivos

En esta pr
actica se usar
a Java para introducir conceptos basicos de comunicacion
sncrona en programas distribuidos, en concreto los objetivos de esta practica
son:
Implementaci
on de la comunicacion entre un cliente y servidor basandose
en el protocolo TCP en Java.
Manejar el API y la documentacion de Java para encontrar la informacion
necesaria.
El entorno de desarrollo a utilizar sera JDK 1.7.

2.

Contenidos

En esta secci
on se presenta el problema objeto de esta practica y se establecen
los ejercicios a realizar. La pr
actica consta de tres ejercicios. Para la realizacion
del segundo ejercicio es necesario haber comprendido y probado el primer
ejercicio.

2.1.

La abstracci
on de socket y el modelo cliente/servidor

En la actualidad el modelo mas utilizado para el desarrollo de aplicaciones


en red es el cliente/servidor. Un servidor es un proceso que ofrece una o mas
operaciones que son accesibles a traves de la red. Por otro lado, un cliente es un
proceso que invoca de forma remota las operaciones ofrecidas por un servidor.
El proceso servidor est
a a la espera de recibir invocaciones por parte de sus
clientes. En el momento de recibir una invocacion concreta, internamente la
procesa y devuelve al proceso cliente un resultado.

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

La comunicaci
on entre los procesos cliente y servidor tiene lugar a traves
de la abstracci
on denominada com
unmente socket. Los sockets representan los
extremos de la conexi
on que se establece para llevar a cabo esta comunicacion.
Cuando dos procesos requieren comunicarse solicitan al sistema operativo la
creaci
on de un socket. La respuesta a esta solicitud es un identificador que
permite al proceso hacer referencia al nuevo socket creado. Atendiendo a la pila
de protocolos de Internet existen dos tipos de sockets:
Sockets orientados a comunicacion sncrona. El uso de este tipo de sockets
proporciona una transmision bidireccional, continua y fiable (los datos se
comunican ordenados y sin duplicados) con conexion mediante el protocolo
TCP (Transport Control Protocol). En Java este tipo de sockets se
implementan mediante las clases java.net.Socket y java.net.ServerSocket.
Sockets orientados a comunicacion asncrona. El uso de este tipo de sockets
proporciona una transmision bidireccional, no fiable, de longitud maxima
prefijada y sin conexi
on mediante el protocolo UDP (User Datagram
Protocol). En Java este tipo de sockets se implementa mediante la clase
java.net.DatagramSocket.
Ambos tipos de sockets tienen asociados un objeto java.io.OutputStream y
un objeto java.io.InputStream mediante los cuales puede emitir y recibir cadenas
de bytes, respectivamente.
En esta pr
actica nos centramos en comunicacion sncrona entre procesos
cliente y servidor. Por tanto trabajaremos con las clases java.net.Socket y
java.net.ServerSocket para el cliente y el servidor, respectivamente.

2.2.

Ejercicios obligatorios

A continuaci
on se describen los tres ejercicios requeridos en esta practica.
Ejercicio 1
El anexo I muestra un ejemplo de proceso servidor que escucha peticiones
de un cliente en un puerto especfico, mientras que el anexo II corresponde al
c
odigo de un cliente que usa dicho servicio. La instruccion
String SERVER_ADDRESS = " localhost " ;

obliga a que el cliente se ejecute en la misma maquina que el servidor.


El proceso servidor est
a asociado al n
umero de puerto indicado en la variable
umero
SERVER PORT. El proceso cliente solicita al proceso servidor que cuente el n
de vocales de las frases que debe introducir el usuario por la entrada estandar.
El proceso servidor atiende las peticiones del cliente y le comunica la respuesta
hasta que recibe la secuencia END OF SERVICE. Cuando recibe esta secuencia el
servidor finaliza su ejecuci
on.
El cliente, en primer lugar, establece una conexion con el servidor para
solicitarle sus servicios. A continuacion, enva las diferentes peticiones de
servicio, recibe las respuestas del servidor e informa al usuario (mediante la
salida est
andar) del n
umero de vocales contabilizadas por el servidor para cada
una de las frases introducidas. Una vez que el usuario introduce la secuencia END
OF SERVICE, el cliente finaliza su ejecuci
on.

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

Ejecutad el servidor en un terminal. A continuacion, abrid un nuevo terminal


y ejecutad el cliente. En este caso el servidor y el cliente se estan ejecutando
en la misma m
aquina; es decir, en local. Analizad el comportamiento de ambos
procesos y las comunicaciones que se establecen entre ellos.
El ejercicio pide modificar ambos programas. En el caso del servidor, el
puerto ser
a un par
ametro de invocacion desde lnea de comandos. En el caso del
cliente, tomar
a dos par
ametros: la IP donde se encuentra el servidor, as como el
puerto en el que escucha. Para probar su ejecucion, debeis averiguar la direccion
IP del ordenador en el que vais a ejecutar el servidor (por ejemplo mediante el
comando ipconfig) y ponerlo en march. A continuacion, ejecutad el cliente en un
ordenador diferente al que ejecuta el servidor (por ejemplo, que el compa
nero
que tengas al lado ejecute su cliente para que invoque el servicio que ofrece tu
servidor). Analizad el comportamiento de ambos procesos y las comunicaciones
que se establecen entre ellos.
Ejercicio 2
En la versi
on anterior el servidor queda asociado y conectado al primera
cliente que se conecte .
Modificad el c
odigo del ejercicio anterior para que el servidor no finalice
despues de atender la llamada de un cliente. Es decir, para que el servidor se
quede a la espera de nuevas peticiones de otros clientes despues de atender a
uno de ellos. Para ello, cuando reciba la peticion de un nuevo cliente, el servidor
debe crear un Thread que atienda la peticion del cliente y quedarse a la espera
de nuevas peticiones de otros clientes.
Ejecutad el servidor en un terminal. A continuacion, ejecutad un cliente en
local y otro en remoto y analizad el comportamiento de los procesos que se crean
y las comunicaciones que se establecen entre ellos.
Ejercicio 3
Construid un proceso servidor que mantenga una matriz de dimension
10 x 4 que represente los asientos de un vagon de tren. Los diferentes asientos
se identifican por la fila y la columna en la que se encuentran. Ademas,
construid procesos clientes que reserven y compren billetes especificando el
asiento concreto, identificado por un n
umero de fila y un n
umero de columna.
Cuando el cliente intenta realizar una compra de billete, el servidor le responde
una de las siguientes opciones:
Reservado. En este caso, el cliente al recibir la respuesta muestra un

mensaje por salida est


andar indicando que la compra se ha realizado
correctamente y finaliza su ejecucion.
Ocupado y una lista de los asientos que se encuentran libres actualmente.

En este caso, el cliente al recibir la respuesta solicita otro asiento hasta


que logre comprar uno que esta libre.
Vag
on completo. En este caso, el cliente, al recibir la respuesta la muestra

por salida est


andar y finaliza su ejecucion.
Implementad un sistema que lance un servidor y un n
umero suficiente de
clientes que simulen el proceso de compra.

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

3.

Entrega de la pr
actica

La pr
actica se realizar
a de forma individual. Cuando se finalice se debe
entregar un fichero comprimido practica 5 miNIP.tar (donde miNIP es el NIP
del autor de los ejercicios) con el siguiente contenido:
1. Un fichero de texto denominado autor.txt que contendra el NIP, los
apellidos y el nombre del autor de la practica en las primeras lneas del
fichero. Por ejemplo:
NIP
Apellidos
Nombre
-----------------------------------------------------345689
Rodr
guez Quintela
Sabela
Opcionalmente, a continuacion, se podra incluir en dicho fichero un
resumen de las principales dificultades encontradas durante la realizacion
de la pr
actica, y notas a considerar.
2. Un directorio denominado src, que contendra los ficheros fuente Java
utilizados en la implementacion de la practica. En el directorio habra un
subdirectorio por cada uno de los ejercicios que hay que entregar en
la presente pr
actica. Los subdirectorios que deben estar presentes son:
practica 5 1, practica 5 2 y practica 5 3.
3. Un fichero de texto para cada uno de los ejercicios incluidos en la practica
que contendr
a un una explicacion del comportamiento de los procesos
que se crean, de las comunicaciones que se establecen entre ellos en
cada ejercicio, de los resultados esperados, de los resultados obtenidos,
de las ventajas e inconvenientes de cada una de las soluciones, de los
posibles problemas que puedan surgir, etc. Cada uno de estos ficheros de
texto deber
a denominarse analisis X Y.txt (donde X Y indica el n
umero
de ejercicio) y contendra el analisis correspondiente al ejercicio X.Y
Los ficheros de texto que deben estar presentes son: analisis 5 1.txt,
analisis 5 2.txt y analisis 5 3.txt.
4. Un fichero ejecutable (shell script) para cada uno de los ejercicios
incluidos en la pr
actica. Cada uno de estos ficheros debera denominarse
compila ejX Y.sh (donde X Y indica el n
umero de ejercicio) y contendra las
instrucciones necesarias para compilar todos los ficheros fuentes Java
(ficheros con extensi
on .java) correspondientes al ejercicio X.Y Los
ficheros ejecutables que deben estar presentes son: compila ej5 1.sh,
compila ej5 2.sh y compila ej 5 3.sh.
5. Un directorio bin, que contendra las libreras necesarias para la ejecucion
de la pr
actica (en caso de emplear alguna librera no estandar) y los
ficheros compilados correspondientes a los ficheros fuente del directorio
src, es decir, en este directorio es donde depositan las clases compiladas
generadas por los ejecutables compilaX Y.sh.
6. Un fichero ejecutable (shell script) para cada uno de los ejercicios
incluidos en la pr
actica. Cada uno de estos ficheros debera denominarse
ejecuta ejX Y.sh (donde X Y indica el n
umero de ejercicio) y contendra las

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

instrucciones necesarias para lanzar la ejecucion de la aplicacion dise


nada
en el ejercicio X.Y. Estos ficheros (shell scripts) deben recibir los
argumentos/par
ametros necesarios para la ejecucion de las aplicaciones
y definir el CLASSPATH necesario (se deben referenciar los directorios
propios con un path relativo) utilizando la opcion de compilacion -cp o
-classpath de javac. Los ficheros ejecutables que deben estar presentes
son: ejecuta ej5 1.sh, ejecuta ej5 2.sh y ejecuta ej5 3.sh.
Al descomprimir el fichero .tar se deben extraer los ficheros y directorios
indicados en el directorio practica 5 miNIP (donde miNIP es el NIP del autor de
la pr
actica). Es importante seguir las convenciones de nombrado y la estructura
de ficheros y directorios (src, bin, etc.) descrita.
Para la entrega del fichero .tar, se utilizara el programa someter en la
m
aquina hendrix-ssh.cps.unizar.es. La practica debera estar sometida antes
del inicio de la siguiente sesi
on de practicas del grupo correspondiente.

4.

Procedimiento
recomendaciones

de

correcci
on

Una vez realizadas las pr


acticas y entregadas estas, cada estudiante debe
present
arselas al profesor de practicas en la siguiente sesion de laboratorio. Al
realizar la presentaci
on el profesor le formulara cuestiones sobre las decisiones
de dise
no e implementaci
on que ha realizado.
La pr
actica debe entregarse en los terminos indicados anteriormente,
funcionar correctamente en cualquier ordenador con Java 1.7 y no haber
sido copiada. En particular, hay que asegurarse de que la practica funciona
correctamente en los ordenadores del laboratorio (vigilad aspectos como los
permisos de ejecuci
on de los scripts, juego de caracteres utilizado en los ficheros,
etc.). Tambien es importante someter codigo limpio (donde se ha evitado
introducir mensajes de depuracion que no proporcionan informacion al usuario).
El tratamiento de errores debe ser adecuado, de forma que si se producen debera
informarse al usuario del tipo de error producido. Ademas se consideraran los
siguientes aspectos:
1. La estructura (clases estructuradas adecuadamente en paquetes, metodos,
visibilidad atributos y metodos, etc.).
2. La interfaz de usuario.
3. El adecuado formateado de los documentos. Los ficheros de codigo
fuente deber
an incluir, en sus primeras lneas, un comentario en el
que se resuma el objetivo o funcionalidad del codigo y el nombre y
apellidos del autor del mismo, junto con la fecha de su realizacion. Es
conveniente seguir alg
un esquema de codificacion. En el caso de Java, una
buena referencia puede ser http://www.oracle.com/technetwork/java/
codeconventions-150003.pdf.

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

Anexo I: La clase
/*
* File :
* Author :
* Date :
* Coms :
*
*
*/

Servidor

Servidor . java
PSCD - Unizar
04/11/14
Programaci
o n de Sistemas Concurrentes y
Distribuidos Curso 2014 -2015.
Ejemplo de servidor con comunicaci
o n por sockets

// package practica5 . ejercicio1 ;


import
import
import
import
import
import

java . io . IOException ;
java . net . Socket ;
java . net . ServerSocket ;
java . io . PrintWriter ;
java . io . BufferedReader ;
java . io . InputStreamReader ;

public class Servidor {


public static void main ( String [] args ) {
int SERVER_PORT = 2000;
// El servidor escuchar
a en local
// en el puerto SERVER_PORT ( >= 1024)
ServerSocket serverSocket = null ; // para escuchar
Socket clientSocket = null ;
// uno por cliente
// Inicializar el socket del cliente con el que se va
// a comunicar el servidor , es decir se acepta la
// conexi
o n de un cliente al servidor mediante
// el m
e todo accept ()
serverSocket = creaListenSocket ( SERVER_PORT );
// En este ejemplo , s
o lo uno . En un caso general
// un servidor tendr
a esto en un bucle , creando
// uno por cada nuevo cliente
clientSocket = creaClientSocket ( serverSocket );
//
//
//
//
//

Inicializar los canales de comunicaci


o n usados en
el socket para comunicarse con el cliente .
El OutputStream permite enviar mensajes al cliente
El InputStream permite recibir al servidor
mensajes emitidos por el proceso cliente

PrintWriter salHaciaCliente = null ;


BufferedReader entDesdeCliente = null ;
try {
salHaciaCliente = new PrintWriter (
clientSocket . getOutputStream () , true );
entDesdeCliente = new BufferedReader (

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

new InputStreamReader (
clientSocket . getInputStream ()
)
);
} catch ( IOException e ) {
System . err . println ( e );
System . exit ( -1);
}
// Contar vocales de frases enviadas por el cliente
String inputLine = " " ;
try {
inputLine = entDesdeCliente . readLine ();
while (( inputLine != null )
&& (! inputLine . equals ( " END OF SERVICE " ))) {
// Calcular el n
u mero de vocales que
// tiene la respuesta .
String respuesta = " " + inputLine + " has " +
+ numeroDeVocales ( inputLine ) + " vowels " ;
// Enviar la respuesta al cliente
salHaciaCliente . println ( respuesta );
// Recibir nueva petici
o n del cliente
inputLine = entDesdeCliente . readLine ();
}
// Al cerrar cualquier canal de comunicaci
on
// usado por un socket , el socket se cierra .
// Para asegurarse que se env
n las respuestas que
// est
a en el buffer cerramos el OutputStream .
salHaciaCliente . close ();
// Cierra el servidor de sockets
serverSocket . close ();
} catch ( IOException e ) {
System . err . println ( e );
System . exit ( -1);
}
System . out . println ( " Bye , bye . " );
}

// Crea un socket de servidor


// Aborta programa si no lo logra
private static
ServerSocket creaListenSocket ( int serverSockNum ){
ServerSocket server = null ;
try {
server = new ServerSocket ( serverSockNum );
} catch ( IOException e ) {

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

System . err . println ( " Problems in port : " +


serverSockNum );
System . exit ( -1);
}
return server ;
}
// Establece conexi
o n con server y devuelve socket
// Aborta programa si no lo logra
private static
Socket creaClientSocket ( ServerSocket server ){
Socket res = null ;
try {
res = server . accept ();
} catch ( IOException e ) {
System . err . println ( " Accept failed . " );
System . exit (1);
}
return res ;
}
// Devuelve num vocales de frase
private static int numeroDeVocales ( String frase ) {
int res = 0;
String fraseMin = frase . toLowerCase ();
for ( int i = 0; i < fraseMin . length (); ++ i ) {
switch ( fraseMin . charAt ( i )) {
case a : case
a :
case e : case
e :
case i : case
:
case o : case
o :
case u : case
u :
res ++;
break ;
default :
// ignoramos las dem
a s letras
}
}
return res ;
}
}

Anexo II: La clase


/*
*
*
*
*
*

File :
Author :
Date :
Coms :

Cliente

Cliente . java
PSCD - Unizar
04/11/14
Programaci
o n de Sistemas Concurrentes y
Distribuidos Curso 2014 -2015.

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

*
Ejemplo de cliente con comunicaci
o n por sockets
*/
// package practica5 . ejercicio1 ;
import
import
import
import
import
import

java . io . IOException ;
java . net . Socket ;
java . net . UnknownHostException ;
java . io . PrintWriter ;
java . io . BufferedReader ;
java . io . InputStreamReader ;

public class Cliente {


// Para almacenar la direcci
on
// y n
u mero de puerto donde escucha el
// proceso servidor
static private String SERVER_ADDRESS = " localhost " ;
static private int SERVER_PORT = 2000;
// Creaci
o n del socket con el que se llevar
a a cabo
// la comunicaci
o n con el servidor .
static private Socket socketAlServidor = null ;

public static void main ( String [] args ) {


boolean exito ; // conectado ?
exito = conectarServidor (10); // 10 intentos
if (! exito ){
System . err . println ( " Don t know about host : "
+ SERVER_ADDRESS );
System . exit (1); // abortar si hay problemas
}

// Ya hay conex

on
// Inicializaci
o n de los flujos de datos del socket
// para la comunicaci
o n con el servidor
PrintWriter can alSa lida AlSer vido r = null ;
BufferedReader ca n al En t ra d aD el S er v id or = null ;
try {
can alSa lida AlSer vido r = new PrintWriter (
socketAlServidor . getOutputStream () ,
true
);
c an al E nt r ad a De lS e rv i do r = new BufferedReader (
new InputStreamReader (
socketAlServidor . getInputStream ()
)
);
} catch ( IOException e ) { // abortar si hay problemas
System . err . println ( " I / O problem : " + SERVER_ADDRESS );

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

10

System . exit (1);


}
// Definici
o n de un buffer de entrada para leer
// de la entrada standard .
BufferedReader entradaStandard = new BufferedReader (
new InputStreamReader ( System . in ));
String userInput = " " ;
// Protocolo de comunicaci
o n con el Servidor .
// Mientras no se reciba la secuencia
// " END OF SERVICE " el servidor contar
a el n
u mero
// de vocales que aparecen en las frases que le
// env
a el cliente . El cliente obtiene las frases
// que le pasa al servidordel usuario que lo
// est
a ejecutando .
try {
while (!( userInput . equals ( " END OF SERVICE " ))) {
System . out . print ( " Text : " );
userInput = entradaStandard . readLine ();
if ( userInput != null ) {
can alSa lida AlSer vido r . println ( userInput );
String respuesta = ca n al En t ra d aD e lS er v id o r
. readLine ();
if ( respuesta != null ) {
System . out . println ( " Server answer : "
+ respuesta );
} else {
System . out . println ( " Comm . is closed ! " );
}
} else {
System . err . println ( " Wrong input ! " );
}
}
// Al cerrar cualquiera de los canales de
// comunicaci
o n usados por un socket , el socket
// se cierra . Como no nos importa perder informaci
on
// cerramos el canal de entrada .
c an al E nt r ad a De lS e rv i do r . close ();
// Cierre del Socket para comunicarse con el servidor .
socketAlServidor . close ();
} catch ( Exception e ){
System . err . println ( e );
}
}
static private boolean conectarServidor ( int maxIntentos ){
// hasta maxIntentos intentos de conexi
o n , para
// darle tiempo al servidor a arrancar
boolean exito = false ; // hay servidor ?
int van = 0;

Programaci
on de Sistemas Concurrentes y Distribuidos, curso 14-15

while (( van < maxIntentos ) && ! exito ){


try {
socketAlServidor = new Socket (
SERVER_ADDRESS , SERVER_PORT );
exito = true ;
} catch ( Exception e ) {
van ++;
System . err . println ( " Failures : " + van );
try { // esperar 1 seg
Thread . sleep (1000);
} catch ( InterruptedException e2 ) {
e2 . printStackTrace ();
}
}
}
return exito ;
}
}

11

Potrebbero piacerti anche