Вы находитесь на странице: 1из 9

Prctica 5: Implementacin en Java de sistemas

cliente/servidor basados en comunicacin


sncrona
Programacin de Sistemas Concurrentes y Distribuidos
Grado de Ingeniera Informtica
Dpto. de Informtica e Ingeniera de Sistemas,

1. Objetivos
En esta prctica se usar Java para introducir conceptos bsicos de comunicacin
sncrona en programas distribuidos, en concreto los objetivos de esta prctica son:
Implementacin de la comunicacin entre un cliente y servidor basndose en el
protocolo TCP en Java. Manejar el API y la documentacin de Java para encontrar la
informacin
necesaria. El entorno de desarrollo a utilizar ser JDK

2. Contenidos
En esta seccin se presenta el problema objeto de esta prctica y se establecen los
ejercicios a realizar. La prctica consta de tres ejercicios. Para la realizacin del
segundo ejercicio es necesario haber comprendido y probado el primer ejercicio.

2.1. La abstraccin de socket y el modelo cliente/servidor


En la actualidad el modelo ms utilizado para el desarrollo de aplicaciones en red es el
cliente/servidor. Un servidor es un proceso que ofrece una o ms operaciones que son
accesibles a travs 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 la
espera de recibir invocaciones por parte de sus clientes. En el momento de recibir una
invocacin concreta, internamente la procesa y devuelve al proceso cliente un
resultado.
La comunicacin entre los procesos cliente y servidor tiene lugar a travs de la
abstraccin denominada comnmente socket. Los sockets representan los extremos de
la conexin que se establece para llevar a cabo esta comunicacin. Cuando dos
procesos requieren comunicarse solicitan al sistema operativo la creacin 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
comunicacin sncrona. El uso de este tipo de sockets proporciona una transmisin
bidireccional, continua y fiable (los datos se comunican ordenados y sin duplicados)
con conexin 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
comunicacin asncrona. El uso de este tipo de sockets proporciona una transmisin
bidireccional, no fiable, de longitud mxima prefijada y sin conexin 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 prctica nos centramos en comunicacin 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 continuacin se describen los tres ejercicios requeridos en esta prctica.
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 cdigo de un
cliente que usa dicho servicio. La instruccin String SERVER_ADDRESS = " localhost ";
obliga a que el cliente se ejecute en la misma mquina que el servidor. El proceso
servidor est asociado al nmero de puerto indicado en la variable SERVER PORT. El
proceso cliente solicita al proceso servidor que cuente el nmero
de vocales de las frases que debe introducir el usuario por la entrada estndar.
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 ejecucin.
El cliente, en primer lugar, establece una conexin con el servidor para solicitarle sus
servicios. A continuacin, enva las diferentes peticiones de servicio, recibe las
respuestas del servidor e informa al usuario (mediante la salida estndar) del nmero
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
ejecucin.
Ejecuta el servidor en un terminal. A continuacin, abre un nuevo terminal y ejecutad el
cliente. En este caso el servidor y el cliente se estn ejecutando en la misma mquina;
es decir, en local. Analiza 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 un
parmetro de invocacin desde lnea de comandos. En el caso del cliente, tomar dos
parmetros: la IP donde se encuentra el servidor, as como el puerto en el que escucha.
Para probar su ejecucin, debes averiguar la direccin IP del ordenador en el que vas a
ejecutar el servidor (por ejemplo mediante el comando ipconfig) y ponerlo en march. A
continuacin, ejecuta el cliente en un
ordenador diferente al que ejecuta el servidor (por ejemplo, que el compaero 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.

3. Entrega de la prctica
La prctica se realizar de forma individual. Cuando se finalice se debe entregar un
fichero comprimido prctica 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 contendr el NIP, los apellidos y el
nombre del autor de la prctica en las primeras lneas del fichero. Por ejemplo:
NIP Apellidos Nombre
-----------------------------------------------------345689 Rodrguez Quintela Sabela

A continuacin, se podr incluir en dicho fichero un resumen de las principales


dificultades encontradas durante la realizacin de la prctica, y notas a considerar.
2. Un directorio denominado src, que contendr los ficheros fuente Java utilizados
en la implementacin de la prctica. En el directorio habr un subdirectorio por
cada uno de los ejercicios que hay que entregar en la presente prctica. Los
subdirectorios que deben estar presentes son:
practica 1 1, pr

.
3. Un fichero de texto para cada uno de los ejercicios incluidos en la prctica que
contendr una explicacin 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
denominarse anlisis X Y.txt (donde X Y indica el nmero de ejercicio) y contendr el
anlisis correspondiente al ejercicio X.Y Los ficheros de texto que deben estar
presentes son: anlisis 5 1.txt, anlisis 5 2.txt y anlisis 5 3.txt.
4. Un fichero ejecutable (shell script) para cada uno de los ejercicios incluidos en la
prctica. Cada uno de estos ficheros deber denominarse compila ej X Y.sh (donde X Y
indica el nmero de ejercicio) y contendr las instrucciones necesarias para compilar
todos los ficheros fuentes Java
(ficheros con extensin .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 contendr las libreras necesarias para la ejecucin de la
prctica (en caso de emplear alguna librera no estndar) 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
prctica. Cada uno de estos ficheros deber denominarse ejecuta ejX Y.sh (donde X Y
indica el nmero de ejercicio) y contendr las instrucciones necesarias para lanzar la
ejecucin de la aplicacin diseada en el ejercicio X.Y. Estos ficheros (shell scripts)
deben recibir los argumentos/parmetros necesarios para la ejecucin de las
aplicaciones y definir el CLASSPATH necesario (se deben referenciar los directorios
propios con un path relativo) utilizando la opcin de compilacin -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 prctica). 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 utilizar el programa someter en la mquina hendrixssh.cps.unizar.es. La prctica deber estar sometida antes del inicio de la siguiente
sesin de prcticas del grupo correspondiente.

4. Procedimiento de correccin y recomendaciones


Una vez realizadas las prcticas y entregadas estas, cada estudiante debe
presentrselas al profesor de prcticas en la siguiente sesin de laboratorio. Al realizar
la presentacin el profesor le formular cuestiones sobre las decisiones de diseo e
implementacin que ha realizado.
La prctica debe entregarse en los trminos indicados anteriormente, funcionar
correctamente en cualquier ordenador con Java y no haber sido copiada. En
particular, hay que asegurarse de que la prctica funciona correctamente en los
ordenadores del laboratorio (vigilar aspectos como los permisos de ejecucin de los
scripts, juego de caracteres utilizado en los ficheros, etc.). El tratamiento de errores
debe ser adecuado, de forma que si se producen deber informarse al usuario del tipo
de error producido. Adems se considerarn los siguientes aspectos:

1. La estructura (clases estructuradas adecuadamente en paquetes, mtodos,


visibilidad atributos y mtodos, etc.).
2. La interfaz de usuario.
3. El adecuado formateado de los documentos. Los ficheros de cdigo fuente debern
incluir, en sus primeras lneas, un comentario en el que se resuma el objetivo o
funcionalidad del cdigo y el nombre y apellidos del autor del mismo, junto con la fecha
de su realizacin. Es conveniente seguir algn esquema de codificacin. En el caso de
Java,
una
buena
referencia
puede
ser
http://www.oracle.com/technetwork/java/codeconventions-150003.pdf.

Anexo I: La clase

Servidor
/*
* File : Servidor . java
* Author :
* Date
* Coms : Programacin de Sistemas Concurrentes y
* Distribuidos Curso 2014 -2015.
* Ejemplo de servidor con comunicacin por sockets
*/
// package practica5 . ejercicio1 ;
import java .io. IOException ;
import java .net . Socket ;
import java .net . ServerSocket ;
import java .io. PrintWriter ;
import java .io. BufferedReader ;
import java .io. InputStreamReader ;
public class Servidor {
public static void main ( String [] args ) {
int SERVER_PORT = 2000;
// El servidor escuchara 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
// conexin de un cliente al servidor mediante
// el mtodo accept ()
serverSocket = creaListenSocket ( SERVER_PORT );
// En este ejemplo , solo uno . En un caso general
// un servidor tendra esto en un bucle , creando
// uno por cada nuevo cliente
clientSocket = creaClientSocket ( serverSocket );
// Inicializar los canales de comunicacin 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 (
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 nmero de vocales que
// tiene la respuesta .
String respuesta = "" + inputLine + " has " +
+ numeroDeVocales ( inputLine ) + " vowels ";
// Enviar la respuesta al cliente
salHaciaCliente . println ( respuesta );
// Recibir nueva peticin del cliente
inputLine = entDesdeCliente . readLine ();
}
// Al cerrar cualquier canal de comunicacin
// usado por un socket , el socket se cierra .
// Para asegurarse que se envn las respuestas que
// est 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) {
System .err . println (" Problems in port : " +
serverSockNum );
System . exit ( -1);
}
return server ;
}
// Establece conexin 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 :
case e: case :
case i: case :
case o: case :
case u: case :
res ++;
break ;
default :
// ignoramos las dems letras
}
}
return res;
}
}

Anexo II: La clase

Cliente
/*
* File : Cliente . java
* Author :
* Coms : Programacin de Sistemas Concurrentes y
* Distribuidos Curso 2014 -2015.

Programacin de Sistemas Concurrentes y Distribuidos, curso 14-15 9


* Ejemplo de cliente con comunicacin por sockets
*/
// package practica5 . ejercicio1 ;
import java .io. IOException ;
import java .net . Socket ;
import java .net . UnknownHostException ;
import java .io. PrintWriter ;
import java .io. BufferedReader ;
import java .io. InputStreamReader ;
public class Cliente {
// Para almacenar la direccin
// y nmero de puerto donde escucha el
// proceso servidor
static private String SERVER_ADDRESS = " localhost ";
static private int SERVER_PORT = 2000;
// Creacin del socket con el que se llevar a a cabo
// la comunicacin 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 conexin
// Inicializacin de los flujos de datos del socket
// para la comunicacin con el servidor
PrintWriter canalSalidaAlServidor = null ;
BufferedReader canalEntradaDelServidor = null ;
try {
canalSalidaAlServidor = new PrintWriter (
socketAlServidor . getOutputStream (),
true

);
canalEntradaDelServidor = new BufferedReader (
new InputStreamReader (
socketAlServidor . getInputStream ()
)
);
} catch ( IOException e) { // abortar si hay problemas
System .err . println ("I/O problem :" + SERVER_ADDRESS );
System . exit (1);
}
// Definicin de un buffer de entrada para leer
// de la entrada standard .
BufferedReader entradaStandard = new BufferedReader (
new InputStreamReader ( System .in ));
String userInput = "";
// Protocolo de comunicacin con el Servidor .
// Mientras no se reciba la secuencia
// " END OF SERVICE "el servidor contara el nmero
// de vocales que aparecen en las frases que le
// enva el cliente . El cliente obtiene las frases
// que le pasa al servidordel usuario que lo
// est ejecutando .
try{
while (!( userInput . equals ("END OF SERVICE "))) {
System . out . print (" Text : ");
userInput = entradaStandard . readLine ();
if ( userInput != null ) {
canalSalidaAlServidor . println ( userInput );
String respuesta = canalEntradaDelServidor
. 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
// comunicacin usados por un socket , el socket
// se cierra . Como no nos importa perder informacin
// cerramos el canal de entrada .
canalEntradaDelServidor . 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 conexin , para
// darle tiempo al servidor a arrancar
boolean exito = false ; // hay servidor ?
int van = 0;
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 ;
}
}

Вам также может понравиться