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