Download sistema de distribución de carga para cluster de

Document related concepts
no text concepts found
Transcript
SISTEMA DE DISTRIBUCIÓN DE
CARGA PARA CLUSTER DE
SERVIDORES
Proyecto de Investigación I y II.
CBI.
Universidad Autónoma Metropolitana.
Licenciatura en Computación.
Asesora: Graciela Román Alonso.
Trimestre: 04-O.
Autor: Miguel Angel García Vidal.
Agradecimientos.
A mí querida Madre y Abuela,
por haberme ayudado a terminar mis estudios profesionales.
A mí amada Novia,
por todo el apoyo que me ha dado durante toda la carrera
siempre creyendo que podía hacer las cosas mejor.
A mis maestros,
que me han enseñado tanto en estos años
para prepararme hacia el futuro.
A la Universidad,
y sobre todo a los encargados de los laboratorios
de Sistemas distribuidos,
Supercómputo y visualización en Paralelo
y de Docencia,
donde pude realizar las pruebas de este proyecto.
1
ÍNDICE.
I. Introducción
3
II. Objetivos del Proyecto.
5
III. El lenguaje Java.
6
IV. Arquitectura Propuesta.
8
-
El Servidor.
9
-
El Servidor Principal.
11
-
Cliente.
11
-
Archivos de configuración.
12
-
Clase Peticiones.
13
V. Pruebas y Resultados.
14
-
Prueba 1.
14
-
Prueba 2.
14
-
Prueba 3.
15
VI. Conclusiones.
16
Bibliografía.
17
Anexos.
18
-
Anexo A Server.java
18
-
Anexo B ServidorA.java
20
-
Anexo C Atención.java
23
-
Anexo D Transferencia.java
25
-
Anexo E ServerG.java
27
-
Anexo F ServidorG.java
29
-
Anexo G Cliente.java
31
-
Anexo H Cliente2.java
34
-
Anexo I Peticiones.java
37
-
Anexo J Peticiones2.java
39
2
I. INTRODUCCIÓN:
Las computadoras han mejorado la vida de muchas maneras, y con la aparición
del Internet, esto a dado lugar a que día a día miles de usuarios se comuniquen a través
del mundo para realizar múltiples actividades que van desde consulta de información en
páginas Web a manejo de enormes Bases de Datos de forma remota. Es por esto que ha
surgido el término de cliente/servidor.
El término cliente/servidor describe un sistema en el que una máquina cliente
solicita a una segunda máquina llamada servidor que ejecute una tarea específica. El
cliente suele ser una computadora personal común conectada a una LAN, y el servidor,
por lo general es una máquina anfitriona, como un servidor de archivos PC, un servidor
de archivos de UNIX o una macrocomputadora o computadora de rango medio.
El programa cliente cumple dos funciones distintas: por un lado gestiona la
comunicación con el servidor, solicita un servicio y recibe los datos enviados por aquél.
Por otro, maneja la interfaz con el usuario: presenta los datos en el formato adecuado y
brinda las herramientas y comandos necesarios para que el usuario pueda utilizar las
prestaciones del servidor de forma sencilla.
El programa servidor en cambio, básicamente sólo tiene que encargarse de
transmitir la información de forma eficiente. No tiene que atender al usuario. De esta
forma un mismo servidor puede atender a varios clientes al mismo tiempo. Algunas de
las principales LAN cliente/servidor con servidores especializados que pueden realizar
trabajos para clientes incluyen a Windows NT, NetWare de Novell, VINES de Banyan
y LAN Server de IBM entre otros. Todos estos sistemas operativos de red pueden
operar y procesar solicitudes de aplicaciones que se ejecutan en clientes, mediante el
procesamiento de las solicitudes mismas.
3
Figura 1.
El desarrollo actual de sistemas cliente servidor se basa en la idea de máquinas
muy poderosas que pueden atender a diversos clientes al mismo tiempo o dos servidores
que atiendan las llamadas por separado. Esto podrá ser bueno para un número de
clientes determinados pero a gran escala como lo es Internet el sistema se hará lento y
en algunas ocasiones negará el servicio o simplemente no hará caso de un nuevo cliente.
Es por esto que actualmente se esta investigando los beneficios que se
obtendrían al utilizar una arquitectura de Clusters, para de esta manera mejorar el
rendimiento. Pero ¿qué es un Cluster? y ¿qué es la distribución de carga?
Un cluster es un número de computadoras unidas por un canal de
comunicaciones o una red, que comparten la misma base de datos, archivos de
configuración, etc. Son utilizadas para hacer labores que requieren mucho poder de
procesamiento y tiempo, asignándoles a cada una de las máquinas diferente tarea, es por
eso que se requiere de una distribución de carga bien balanceada para evitar que unas
maquinas no hagan nada mientras otras están muy ocupadas. Para poder realizar bien
esta distribución de carga existen diversos algoritmos de balanceo, que dependiendo de
la demanda y configuración requerida para el Cluster, sirven mejor o peor.
Es por esto que en el presente proyecto se implementara un sistema de clienteservidor mediante un cluster junto con un sistema de distribución, y de esta forma poder
sentar las bases para futuras implementaciones de diversos algoritmos de balanceo de
carga, para una distribución optima.
4
II. OBJETIVO DEL PROYECTO
El objetivo de éste proyecto es presentar las ventajas de tener un cluster de
servidores con distribución de carga, por medio de un algoritmo de balance de carga.
Entre las ventajas que podemos mencionar se encuentran:
•
Es un sistema mucho más económico, ya que no requiere de maquinas muy
poderosas y obviamente costosas para realizar las tareas; de hecho se puede
hacer con un número dado de computadoras personales.
•
Es fácil de construir, solo se necesita crear una red, y los sistemas operativos
adecuados como pueden ser:
o Windows NT, 2000, XP, 2003 Server.
o Unix, FreeBSD, Linux, Novell.
•
Es más rápido, confiable y escalable.
5
III. El lenguaje Java.
El lenguaje Java es un lenguaje de alto nivel que fue creado por la empresa Sun
Microsystems no para uso académico como Pascal, ni fue hecho por una sola persona
como C o C++ sino que fue concebido con motivos comerciales, ya que generó un
interés avasallador debido a su fácil compatibilidad con la WEB.
Los programas en Java consisten en piezas llamadas clases y métodos; de esta
forma se pueden programar los componentes que vayamos a utilizar para crear nuestro
programa, pero la mayoría de programas hechos en Java utilizan las clases y métodos ya
creados; a esto se le llama reutilización del código en la programación orientada a
objetos. De esta manera uno utiliza los componentes ya creados encontrados en
colecciones de clases que existen ya en bibliotecas. Es por esta versatilidad que se
escogió a Java para la realización de éste proyecto.
Por lo general, los sistemas Java constan de varias partes: un entorno, el
lenguaje, la interfaz del programa o API y diversas clases con sus métodos. Para
programar en Java como en cualquier lenguaje es necesario pasar por las fases de
edición, compilación, carga, verificación y ejecución.
Para editar el código se utiliza cualquier editor de texto y el archivo creado se
guarda con extensión .java, hay editores que ofrecen más cosas (ayuda de clases,
autocorrección, diferentes colores para las clases, etc.) como lo son eclipse y
javacreator.
Para compilar un archivo en java se emite el comando javac, el compilador
traduce el programa a código de bytes, que es el lenguaje que entiende el interprete de
Java. Si el archivo se compila correctamente creara un archivo con el mismo nombre
pero con extensión .class, si no, marcará las clases donde hubo errores.
Antes de ejecutar el programa, es necesario colocarlo en la memoria. Esto lo
hace el cargador de clases que toma el archivo o archivos .class y os transfiere a
memoria. Esto se hace con el comando java, con lo cual ya después antes de que el
intérprete ejecute el código de bytes son verificados para que sean validos y no violen
las restricciones de seguridad de Java. Por ultimo la computadora interpreta el código y
lo ejecuta.
6
Las clases que se utilizaron para la comunicación entre el cliente y el servidor,
que de hecho son dos fueron la clase Socket y la clase ServerSocket, estas dos clases se
utilizan para abrir puertos y poder enviar información por esos canales sin importarnos
el como se envía la información por la red, ni mucho menos, o sea, simplemente se le
dan los bites a mandar y del otro lado simplemente los recibe.
Otra clase muy importante que se utilizo fue la clase Threads con la cual se
crean hilos de ejecución, para poder hacer un poco más óptimo el servicio de nuestro
servidor al poder ir atendiendo a varios clientes al mismo tiempo por ejemplo.
Por ultimo otras de las clases importantes que se utilizaron fueron las clases
FileInputStream y BufferedReader que se utilizan para poder escribir y leer de los
archivos respectivamente.
La versión de Java utilizada para la realización de este proyecto fue la
j2sdk1.4.2_04, s, para mayor información sobre las versiones de Java y las clases
disponibles se puede consultar la ayuda en línea de Sun para Java o descargarla del sitio
de Internet que se encuentra en la Bibliografía.
7
IV. ARQUITECTURA PROPUESTA:
La propuesta es hacer un cluster de servidores que atenderán a varios
clientes. Éste cluster tendrá que contener a un servidor primario el cual
balanceará la carga de peticiones entre los demás servidores que componen al
mismo.
Clientes
Internet
O
Red Local
Servidor.
Principal.
Servidores
Base de Datos
Figura 2.
Cada uno de los servidores que componen el cluster deberá de atender
las peticiones de diversos clientes que el servidor principal les envía con
solicitud de archivos en una ruta dada por estos clientes que puede estar en
una base de datos, como se muestra en la Figura 2.
8
Para que el servidor haga esto de una manera eficiente, se utiliza una
cola de peticiones, la cual va almacenando el socket de donde llega la petición
de cada uno de los clientes.
Dicha cola es un hilo que solo se encarga de encolar estas solicitudes de
los clientes, para posteriormente ser sacadas y atendidas por el servidor.
El servidor en si va sacando de esta cola un número dado de peticiones
y se pone a atenderlas; esta atención la va haciendo en una forma simultánea
gracias a que crea un número determinado de procesos hijos en forma de hilos,
los cuales tienen la función de atender al cliente enviando la información, o en
este caso, el archivo solicitado.
El Servidor.
El Servidor normal se compone esencialmente de tres clases como se
muestra en la Figura 3 las cuales son:
•
ServidorA.class
•
Atención.class
•
Transferencia.class
La primera clase contiene a las otras dos, las cuales son clases que
extienden a la clase Threads; la clase Atención es en si la cola de prioridad,
mientras que la clase Transferencia es la que hace la transferencia de archivos
como su nombre lo indica.
ServidorA.class
Atención.class
Transferencia.class
Figura 3. Server.class.
9
La clase Servidor tiene un arreglo de objetos “Transferencia”, que va
creando conforme va sacando de la cola “Atención” los sockets de los clientes.
Una vez que el hilo de transferencia ha finalizado, el servidor saca otra petición
de la cola y se lo asigna a este hilo ya desocupado. Esto lo viene haciendo en
un ciclo infinito; en caso de que no haya clientes en la cola el sistema se queda
esperando hasta que haya alguno que atender.
La clase Transferencia se crea con un socket; con este socket crea un
canal de comunicaciones entre el servidor y el cliente, una vez ya creado este
canal el cliente manda el nombre del archivo que solicita; con este dato el
objeto Transferencia abre el archivo y se lo va mandando al cliente byte por
byte hasta llegar al final de archivo, tras lo cual cierra el archivo y el socket.
La clase Atención se crea con un número (que será el tamaño de la cola)
y el socket del servidor para una comunicación con éste; cuando éste objeto se
inicializa simplemente se queda esperando a que los clientes lo contacten y los
va encolando. Además cuenta con otros métodos, los cuales el servidor utiliza
para poder hacer las operaciones de sacar de la cola. Por cierto si la cola en
dado momento se llena y recibe otro cliente simplemente el método push
regresa el socket de este ultimo cliente no encolado; esto podrá ser útil en un
futuro para redireccionar este cliente a otro servidor.
Por ultimo existe una cuarta clase que es la que contiene el método main
que es la clase Server.class, la cual crea un objeto de la clase ServidorA y lo
inicializa para posteriormente ponerlo a funcionar.
Arreglo de
clase
Transferencia
Figura 4. Esquema del Servidor
Servidor
Cola
10
El Servidor Principal.
El Servidor principal o ServidorG es el encargado de balancear de cierta
manera la carga de las peticiones realizadas por los clientes a los servidores.
Esta clase es muy parecida a un servidor normal, la diferencia consiste en qué
no crea hilos de transferencia, de hecho utiliza la misma clase de Atención para
poder atender a los clientes, el ServidorG.class simplemente crea la cola de
Atención y va sacando de ella la petición del cliente para decirle que servidor
se le asignará para ser atendido. Esta asignación se hace mediante una cola
circular de los servidores de que consta el cluster. Por último se tiene la clase
ServerG con el método main para inicializar al Servidor principal.
Cola
ServidorG
Figura 5. Esquema del ServidorG.
Cliente.
Por otra parte el cliente es una clase que tiene varios constructores el
más completo necesita: un nombre del servidor o dirección IP, un número de
puerto, un string para el nombre del archivo solicitado y otro string para el
nombre que va a tener el archivo descargado. Esta clase primero envía el
archivo solicitado al servidor y crea un archivo nuevo con el nombre
proporcionado, donde guardará la información que reciba del servidor; la forma
de recibir los datos es en un ciclo infinito que en el momento de que ya no
pueda leer nada por el canal se saldrá de dicho ciclo y cerrara el archivo y el
socket de comunicaciones.
Archivos de Configuración.
11
Se utilizó unos archivos de configuración para poder lograr que los
servidores tuvieran mayor flexibilidad al poder escoger el puerto por el que
escuchan, así como el número de nodos y sus IP o Hostname. Los archivos de
configuración son:
-
Para el Servidor normal.- Este archivo debe de ser un documento de
texto que contenga por línea puerto, numero de clientes a atender al
mismo tiempo y el tamaño de la cola.
Ejemplo:
5000
5
50
-
Para el Servidor General.- Este archivo de configuración contiene por
línea lo siguiente: numero de servidores con que consta el cluster, el
puerto por donde escucha, el tamaño de la cola, el puerto por donde
escuchan los servidores normales y finalmente los IP o Hostname de los
servidores normales que deben de ser el mismo numero de los
indicados arriba.
Ejemplo:
5
6000
100
5000
Host1
Host2
148.206.50.63
148.206.50.65
Host5
Clase Peticiones.
12
Esta clase fue implementada para poder realizar pruebas con el servidor,
la cual utiliza otra clase de cliente especial. Estos clientes tienen las mimas
funcionalidades que los originales, pero con la diferencia que todos son hilo; de
esta forma crea una serie de hilos de clientes, pero para poder hacer esto,
como ya se había dicho antes los clientes necesitan inicializar sus valores.
Esto lo hace leyendo de un archivo de configuración las rutas de los archivos
que cada cliente va a solicitar al servidor y se las da a cada uno de los hilos
clientes para que se comuniquen con el servidor. Por lo que este archivo de
configuración debe ser de la siguiente forma:
< Número de clientes >
< Nombre del servidor o IP >
< Puerto por donde se envía >
< Nombre del archivo cómo se va a guardar en el cliente>
< Nombre del archivo que se solicita (ruta completa)>
< Nombre del archivo cómo se va a guardar en el cliente>
13
V. PRUEBAS Y RESULTADOS.
Se hicieron 3 pruebas con diferente número de servidores y archivos de
diferentes tamaños. Estas pruebas se realizaron con el propósito de comparar
el esquema de un solo servidor contra un Cluster de servidores con el algoritmo
de balanceo que se utiliza en la clase ServidorG. Para poder realizar estas
pruebas se hizo uso de la clase Peticiones, primero en una máquina, después
desde diferentes máquinas, para que las peticiones se realizaran desde
diferente IP, para que de este modo se simulara la petición de muchos clientes
desde diferentes lugares.
Prueba 1.
Prueba 2.
Tamaño de archivos:
• 23K temp.doc
• 398K test1.exe
• 2M
test2.tar.gz
• 4M
test3.tgz
Configuración del Servidor Maestro
(cluster):
Número de servidores
2
Proceso atendido a la vez por cada
servidor
1
Tamaño de la cola
4
Número de clientes.
4
Tiempos:
•
•
•
Real
User
Sys
9 min. 21.240 seg.
0 min. 34.430 seg.
5 min. 20.220 seg.
1
4
4
Tiempos:
•
•
•
Configuración del Servidor Maestro
(cluster):
Número de Servidores.
2
Procesos atendidos por cada servidor. 2
Tamaño de la cola.
10
Número de clientes.
8
Tiempos:
•
•
•
Configuración del Servidor:
Proceso atendido a la vez
Tamaño de la cola
Número de clientes.
Tamaño de archivos:
2M
test1.tar.gz
398K
test2.exe
2M
test3.tar.gz
4M
test4.tgz
2M
test5.tar.gz
398K
test6.exe
2M
test7.tar.gz
4M
test8.tgz
Real 11 min. 35.126 seg.
User 0 min. 34.160 seg.
Sys
5 min. 2.520 seg.
Real 14min. 22.221seg
User 1min. 12.760seg.
Sys 12min. 21.860seg
Configuración del Servidor:
Proceso atendido a la vez
Tamaño de la cola
Número de clientes.
2
10
8
Tiempos:
14
•
•
•
Tamaño de la cola.
Número de clientes.
Real 17min. 13.999seg.
User 1min. 9.180seg.
Sys 11min. 11.670seg.
Prueba 3.
10
8
Tiempos:
Tamaño de archivos:
•
1,3M test1.txt
•
1,3M test2.txt
•
720K test3.mp3
•
1,3M test4.txt
•
7,8M test5.run
•
7,8M test6.run
•
720K test7.mp3
•
720K test8.mp3
•
Real 3min. 14.348seg.
•
User
1min. 16.887seg.
•
Sys
1min. 27.366seg.
Configuración del Servidor:
•
•
•
Proceso atendido a la vez
Tamaño de la cola
Número de clientes.
2
10
8
Tiempos:
Configuración del Servidor Maestro
(cluster)
Número de Servidores.
4
Procesos atendidos por cada servidor. 2
•
Real 20min. 7.382seg.
•
User
1min. 20.187seg.
•
Sys
1min. 25.827seg.
RESULTADOS.
En general las pruebas fueron satisfactorias, ya que como se muestran
en la Gráfica 1 se disminuyo el tiempo de respuesta y transmisión de datos
conforme el cluster era aun más grande a comparación de cuando solo se tenía
un solo servidor, donde como se puede ver los tiempos son altos
Numero de servidores
Numero de servidores
4.5
4
3.5
3
2.5
2
1.5
1
0.5
0
194.348
561.24
862.221
695.126
0
200
400
600
800
1033.9991207.382
1000
1200
1400
Tiempos
15
CONCLUSIONES.
Grafica 1.
Se propuso un sistema de cliente servidor que bajara los tiempos de
transferencia de archivos utilizando un algoritmo de balanceo de carga, lo cual
como las pruebas lo indican se logró exitosamente. No obstante, esto no quiere
decir que se halla llegado a lo óptimo ya que se utilizó un algoritmo de balance
de carga muy sencillo con una cola circular. Esto se puede mejorar en un futuro
sirviéndose de que el Servidor Principal puede comunicarse con los nodos (los
otros servidores) y de esta forma poder saber el estado de sus colas, y de esta
manera poder asignar a un cierto cliente que llegue con alguna petición a el
servidor más indicado.
En conclusión yo diría que este proyecto sirve como un punto de partida
para poder posteriormente hacer pruebas e implementar otros algoritmos de
balanceo dinámico mucho más efectivos de una forma más fácil y con los
cambios mínimos de este proyecto.
16
BIBLIOGRAFÍA.
-
Como Programar en Java.
Deitel y Deitel
Pearson Educación.
-
JavaTM 2 Platform Std. Ed. v1.4.2 Manual.
-
http://java.sun.com/docs
17
ANEXOS
Anexo A. Server.java
/**
* @(#)Server.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Server
{
public static void main(String[] args) {
/* Se crea al servidor con un numero de clientes definido, un puerto
*
y un tamaño de cola.
*/
int num_servers,cola,port;
BufferedReader file;
if(args.length == 0)
{
System.out.println("Iniciando");
port = 50000;
num_servers = 2;
cola = 5;
servidorA s = new servidorA(num_servers,port,cola);
System.out.println("s.inicia");
s.inicia();
}
else
18
{
if(args.length == 0)
{
System.out.println("Error, se debe proporcionar el archivo
de configuración");
System.exit(1);
}
else
{
try
{
file = new BufferedReader(new FileReader(
args[0]) );
).intValue();
port = new Integer(file.readLine() ).intValue();
num_servers = new Integer(file.readLine()
cola = new Integer(file.readLine() ).intValue();
servidorA s = new
servidorA(num_servers,port,cola);
s.inicia();
}
catch(FileNotFoundException fnf)
{
System.out.println("No se encontró el Archivo de
configuracion.");
}
catch(IOException ioe)
{
System.out.println("Error de E/S");
}
}
}
}
}
19
Anexo B. ServidorA.java
/**
* @(#)ServidorA.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
class servidorA
{
private ServerSocket s;
private Transferencia T[];
private Atencion A;
private int max_ctes,port;
private boolean busy;
/*
*
@ServidorA
*
*
max_ctes: es el máximo de clientes.
*
port: es el puerto por el cual va a escuchar.
*
tam: es el tamaño de la cola a crear. *
*
*/
servidorA(int max_ctes,int port,int tam)
{
this.max_ctes = max_ctes;
this.port = port;
try
{
s = new ServerSocket(port);
T = new Transferencia[max_ctes];
for(int i = 0; i< T.length;i++)
{
T[i] = null;
}
A = new Atencion(tam,s);
busy = false;
}
catch(IOException e)
20
{
}
}
System.out.println("Error en servidorA al crearlo");
/*
*
@inicia
*
*
Este método iniciliza el hilo de Atención y se
*
prepara a recibir a todos los clientes utilizando para ello
*
hilos de transferencia.
*
*/
public void inicia()
{
int i = 0;
Socket so;
boolean atendido;
A.start();
System.out.println("Después de A.start");
System.out.println("Valor de i es: "+i);
System.out.println("Valor de max_ctes es: "+max_ctes);
/*******************************************************/
while(true)
{
try
{
System.out.println("Entrando a los hilos");
if(A.i > 0)
{
so = A.pop();
Transferencia");
Transferencia(so);
if(so != null)
{
System.out.println("Creando hilo
atendido = false;
while(!atendido)
{
if(T[i] == null)
{
T[i] = new
T[i].start();
21
}
else
{
atendido = true;
if(T[i].busy == false)
{
T[i] = new
Transferencia(so);
}
T[i].start();
atendido = true;
}
i = (i+1) % max_ctes;
}
else
{
}
}
System.out.println("no hay pop");
}
else
while(A.i == 0 );
System.out.println("Hay cliente");
transferencia");
}
catch(Exception e)
{
System.out.println("Error al crear el hilo de
}
}
/****************************************************/
}
}
22
Anexo C. Atención.java
/**
* @(#)Atencion.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;
class Atencion extends Thread
{
private Socket A[];
public int i;
private ServerSocket serv;
Atencion(int max,ServerSocket s)
{
System.out.println("Creando A de "+max);
A = new Socket[max];
i=0;
serv = s;
}
/*
*
Saca el primer elemento de la cola y recorre todos lo demas
*
regresa el socket y si esta vacía la cola null
*
*/
public Socket pop()
{
Socket s;
int j;
if(i > 0)
{
s = A[0];
for(j=0;j<i-1;j++)
A[j] = A[j+1];
i--;
A[i] = null;
return s;
23
}
else
return null;
}
/*
* Encola las peticiones hechas al servidor
* si se llega al limite de la cola se regresa el socket
* ultimo recibido
*/
private Socket push(Socket s)
{
System.out.println("Encolando");
if(i<A.length)
{
A[i] = s;
i++;
return null;
}
else
return s;
}
public void run()
{
Socket e = null;
while(true)
{
try
{
System.out.println("Aceptando cliente");
e = push( serv.accept() );
}
catch(IOException ioe)
{
System.out.println("Error en el hilo de Atención al
encolar");
}
}
}
}
24
Anexo D. Transferencia.java
/**
* @(#)Transferencia.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.IOException;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.Socket;
public class Transferencia extends Thread
{
public String path;
public Socket connection;
public DataOutputStream out;
public DataInputStream in;
public boolean busy;
/**
* Method Transferencia
*
*
* @param s
*
*/
Transferencia(Socket s)
{
connection = s;
try
{
/*
Creando los canales de comunicación
*/
out = new DataOutputStream(connection.getOutputStream() );
in = new DataInputStream(connection.getInputStream() );
/*
Recibiendo el nombre del archivo a enviar */
path = in.readUTF();
busy = false;
}
25
}
catch(IOException e)
{
System.out.println("Error al obtener el OutputStream");
e.printStackTrace();
System.exit(1);
}
/**
* Method run
*
*
*/
public void run()
{
FileInputStream file;
int b;
try
{
file = new FileInputStream(path);
busy = true;
b = file.read();
while( b != -1)
{
out.writeByte(b);
b = file.read();
}
System.out.println("Cerrando el archivo y el socket");
file.close();
connection.close();
busy = false;
archivo");
}
}
catch(FileNotFoundException e)
{
System.out.println("ERROR: No se encuentra el archivo");
System.exit(1);
}
catch(IOException e)
{
System.out.println("ERROR: b no se pudo crear");
System.out.println("ERROR: No se puede cerrar el Socket o el
}
System.exit(2);
26
}
Anexo E. ServerG.java
/**
* @(#)ServerG.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ServerG
{
public static void main(String[] args)
{
int myport,num_servers,i,tam,Uport;
String servers[];
BufferedReader file;
ServidorG S;
/* Se crea al servidor con un numero de clientes definido, un puerto
*
y un tamaño de cola.
*/
try
{
if( args.length > 0 )
{
file = new BufferedReader(new FileReader( args[0]) );
num_servers = (new Integer(file.readLine())).intValue();
System.out.println(num_servers);
servers = new String[num_servers];
myport = new Integer(file.readLine() ).intValue();
System.out.println(myport);
tam = new Integer(file.readLine() ).intValue();
System.out.println(tam);
Uport = new Integer(file.readLine() ).intValue();
System.out.println(Uport);
27
for(i = 0; i< num_servers;i++)
{
servers[i] = file.readLine();
}
}
else
{
S = new ServidorG(myport,tam,servers,Uport );
S.inicia();
System.out.println("Forma de uso:");
System.out.println("ServerG <puerto> <numero de servidores>
<tamaño de la cola> <archivo>");
}
}
catch(IOException e)
{
System.out.println("Error al inicializar servidorG");
}
}
}
28
Anexo F. ServidorG.java
/**
* @(#)ServidorG.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.IOException;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServidorG
{
private ServerSocket s;
private Atencion a;
private String servers[];
private int Uport;
ServidorG(int port, int size_a,String[] servers,int Xport )
{
try
{
System.out.println("Socketserver");
s = new ServerSocket(port);
System.out.println("Atención");
a = new Atencion(size_a,s);
System.out.println(servers);
this.servers = servers;
System.out.println(Xport);
Uport = Xport;
a.start();
}
catch(IOException e)
{
System.out.println("Error al inicializar el servidorG");
}
}
public void inicia()
{
Socket so;
DataOutputStream out;
int max = servers.length;
29
int i = 0;
try
{
while(true)
{
so = a.pop();
if(so != null)
{
out = new
DataOutputStream(so.getOutputStream() );
out.writeUTF(servers[i]);
out.writeInt(Uport);
out.close();
i = (i + 1) % max;
}
}
}
}
}
catch(IOException e)
{
System.out.println("Error con el socket");
}
30
Anexo G. Cliente.java
/**
* @(#)Cliente.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.net.Socket;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
public class Cliente extends Thread
{
private Socket cliente;
private int port;
private String host_server;
private FileOutputStream file;
String s,o;
/**
* Method Cliente
*
*
*/
public Cliente(String s,String o) {
}
host_server = "localhost";
port = 50000;
this.s = s;
this.o = o;
/**
* Method Cliente
*
*
*/
public Cliente(int port,String server,String s, String o) {
host_server = server;
31
this.port = port;
this.s = s;
this.o = o;
}
/**
* Method inicia
*
*
s: Archivo donde se va a guardar el archivo solicitado.
*
*
o: Archivo solicitado.
*
*/
private void inicia() {
DataInputStream datos;
DataOutputStream msg;
int c;
byte b;
try
{
cliente = new Socket(host_server,port);
datos = new DataInputStream(cliente.getInputStream());
/****************************************************/
/*****
Cambio para el servidor general
*****/
host_server = datos.readUTF();
port = datos.readInt();
System.out.println(host_server);
cliente.close();
cliente = new Socket(host_server,port);
datos = new DataInputStream(cliente.getInputStream());
msg = new DataOutputStream(cliente.getOutputStream());
/*****************************************************/
msg.writeUTF(o);
file = new FileOutputStream(s);
}
System.out.println("Entrando al ciclo de lectura");
while(true)
{
b = datos.readByte();
file.write(b);
}
32
catch(EOFException eof)
{
System.out.println("Se llego al final del archivo");
}
catch(IOException ioe)
{
ioe.printStackTrace();
System.exit(1);
}
try
{
}
}
System.out.println("Cerrando el cliente");
cliente.close();//Se cierra el puerto del cliente
file.close();
}
catch(IOException ioe)
{
ioe.printStackTrace();
System.exit(1);
}
public void run()
{
inicia();
}
33
Anexo H. Cliente2.java
/**
* @(#)Cliente2.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.net.Socket;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
public class Cliente2 extends Thread
{
private Socket cliente;
private int port;
private String host_server;
private FileOutputStream file;
String s,o;
/**
* Method Cliente
*
*
*/
public Cliente2(String s,String o) {
}
host_server = "localhost";
port = 50000;
this.s = s;
this.o = o;
/**
* Method Cliente
*
*
*/
public Cliente2(int port,String server,String s, String o) {
34
host_server = server;
this.port = port;
this.s = s;
this.o = o;
}
/**
* Method inicia
*
*
s: Archivo donde se va a guardar el archivo solicitado.
*
*
o: Archivo solicitado.
*
*/
private void inicia() {
DataInputStream datos;
DataOutputStream msg;
int c;
byte b;
try
{
cliente = new Socket(host_server,port);
datos = new DataInputStream(cliente.getInputStream());
msg = new DataOutputStream(cliente.getOutputStream());
/*****************************************************/
msg.writeUTF(o);
file = new FileOutputStream(s);
}
System.out.println("Entrando al ciclo de lectura");
while(true)
{
b = datos.readByte();
file.write(b);
}
catch(EOFException eof)
{
System.out.println("Se llego al final del archivo");
}
catch(IOException ioe)
{
ioe.printStackTrace();
35
}
try
{
}
}
System.exit(1);
System.out.println("Cerrando el cliente");
cliente.close();//Se cierra el puerto del cliente
file.close();
}
catch(IOException ioe)
{
ioe.printStackTrace();
System.exit(1);
}
public void run()
{
inicia();
}
36
Anexo I. Peticiones.java
/**
* @(#)Peticiones.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
class Peticiones
{
public static void main(String args[])
{
String solicitado="",guardar="",server = "";
Cliente cte[];
BufferedReader file;
int i,num_cte,port;
if(args.length != 0)
{
try
{
inicializar
/*
*Se pretende abrir el archivo de configuración para
*a los clientes con las especificaciones del archivo.
*El archivo debe constar de:
*
*
numero de clientes
*
el nombre o IP del servidor.
*
el puerto por donde debe comunicarse.
*
Una secuencia de rutas de los archivos donde se
37
*
va a guardar el archivo y abajo
*
donde esta el archivo en el servidor
*/
/*Archivo de configuración.*/
file = new BufferedReader(new FileReader( args[0]) );
num_cte = (new
Integer(file.readLine())).intValue();//numero de clientes
server = file.readLine();//hostname del servidor principal
port = (new Integer(file.readLine() )).intValue();//puerto
del servidro principal
cte = new Cliente[num_cte];//Arreglo de clientes.
for(i = 0;i < cte.length;i++)
{
guardar = file.readLine();
System.out.println(guardar);
solicitado = file.readLine();
System.out.println(solicitado);
cte[i] = new Cliente(port,server,guardar,solicitado);
cte[i].start();
}
}
else
{
}
}
file.close();
}
catch(FileNotFoundException e)
{
System.out.println("Error no hay archivo");
}
catch(IOException e)
{
System.out.println("Error de E/S");
}
System.out.println("Error no hay parámetros");
}
38
Anexo J. Peticiones2.java
/**
* @(#)Peticiones2.java
*
* JFC Sample application
*
* @author Miguel Angel García Vidal
* @version 1.00 04/10/04
*/
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
class Peticiones2
{
public static void main(String args[])
{
String solicitado="",guardar="",server = "";
Cliente2 cte[];
BufferedReader file;
int i,num_cte,port;
if(args.length != 0)
{
try
{
inicializar
/*
*Se pretende abrir el archivo de configuración para
*a los clientes con las especificaciones del archivo.
*El archivo debe constar de:
*
*
numero de clientes
*
el nombre o IP del servidor.
*
el puerto por donde debe comunicarse.
*
Una secuencia de rutas de los archivos donde se
*
va a guardar el archivo y abajo
39
*
donde esta el archivo en el servidor
*/
/*Archivo de configuración.*/
file = new BufferedReader(new FileReader( args[0]) );
num_cte = (new
Integer(file.readLine())).intValue();//numero de clientes
server = file.readLine();//hostname del servidor principal
port = (new Integer(file.readLine() )).intValue();//puerto
del servidro principal
cte = new Cliente2[num_cte];//Arreglo de clientes.
for(i = 0;i < cte.length;i++)
{
guardar = file.readLine();
System.out.println(guardar);
solicitado = file.readLine();
System.out.println(solicitado);
cte[i] = new
Cliente2(port,server,guardar,solicitado);
cte[i].start();
}
file.close();
}
else
{
}
}
}
catch(FileNotFoundException e)
{
System.out.println("Error no hay archivo");
}
catch(IOException e)
{
System.out.println("Error de E/S");
}
System.out.println("Error no hay parámetros");
}
40