Diseño de una Herramienta para Visualizar distintas Técnicas de Enrutamiento. Autor: Augusto J. Castillo R. Tutor: Rafael Rivas Estrada. Proyecto de Grado presentado ante la ilustre Universidad de Los Andes como requisito final para optar al título de Ingeniero de Sistemas. UNIVERSIDAD DE LOS ANDES. FACULTAD DE INGENIERIA. ESCUELA DE SISTEMAS. JULIO 2002. Indice. Contenido Pág. Capítulo I: Introducción I.1 Problema planteado................................................................................................ 1 I.2 Objetivos Generales............................................................................................... 2 I.2.1 Objetivos Específicos.......................................................................................... 2 I.3 Metodología............................................................................................................ 2 I.3.1 Fase I: Revisión bibliográfica de los algoritmos de enrutamiento.................. 2 I.3.2 Fase II: Selección de la plataforma de desarrollo............................................ 2 I.3.3 Fase III: Selección del sistema operativo........................................................ 3 I.3.4 Fase IV: Selección de un API para el desarrollo de la GUI............................ 3 I.3.5 Fase V: Revisión bibliográfica del API Swing............................................... 4 I.3.6 Fase VI: Prueba de aplicaciones JFC/Swing................................................... 4 I.3.7 Fase VII: Prueba de los Threads en Java......................................................... 4 I.3.8 Fase VIII: Diseño de las clases........................................................................ 5 I.3.9 Fase IX: Implementación de la capa de ejecución.......................................... 5 Capítulo II: Marco Teórico II.1 Enrutamiento......................................................................................................... 6 II.2 Tipos de Enrutamiento.......................................................................................... 17 II.2.1 Estáticos......................................................................................................... 17 II.2.1.1 Enrutamiento por la trayectoria más corta.............................................. 17 II.2.1.2 Inundación.............................................................................................. 17 II.2.1.3 Enrutamiento basado en flujo................................................................. 17 iii II.2.2 Dinámicos...................................................................................................... 18 II.2.2.1 Enrutamiento por vector de distancia..................................................... 18 II.2.2.2 Enrutamiento por estado de enlace......................................................... 18 II.2.2.3 Enrutamiento jerárquico......................................................................... 19 II.2.2.4 Enrutamiento por difusión...................................................................... 19 II.2.2.5 Enrutamiento por multitransmisión........................................................ 20 II.2.2.6 Calidad de servicio (QoS – Quality of Service)..................................... 20 II.2.2.6.1 Atributos relacionados con el usuario............................................ 21 II.2.2.6.2 Atributos relacionados con la red................................................... 21 II.2.2.6.3 Objetivos......................................................................................... 23 II.2.2.6.4 Normas para regular la calidad de servicio en IP............................ 23 II.2.2.6.5 ¿Qué medir?.................................................................................... 24 II.2.2.6.6 ¿Cómo medir la QoS?..................................................................... 24 II.2.2.6.7 ¿Por qué la necesidad de hacer un sistema de este tipo?................ 25 II.3 Eventos Discretos................................................................................................. 25 II.4 Simulación de redes.............................................................................................. 26 II.5 ¿Qué es JAVA?..................................................................................................... 26 II.6 Programación utilizando hilos de ejecución (Threads)......................................... 27 II.7 ¿Qué es SWING?.................................................................................................. 28 Capítulo III : Diseño y especificaciones. III.1 Entidades que componen la visualización y su interacción con el usuario......... 29 III.1.1 La visualización........................................................................................... 30 III.1.1.1 El menú archivo.................................................................................... 30 iv III.1.1.2 El menú edición..................................................................................... 30 III.1.1.3 El menú ejecución.................................................................................. 31 III.1.2 El enrutador.................................................................................................. 31 III.1.3 La red............................................................................................................ 32 III.1.4 El componente.............................................................................................. 33 III.1.5 Las gráficas de control de flujo de datos...................................................... 34 III.1.6 El paquete..................................................................................................... 34 III.1.7 El Algoritmo................................................................................................. 34 III.2 Interacciones entre los componentes ................................................................ 35 III.2.1 Conexiones de las entidades......................................................................... 35 III.2.1.1 Con el enrutador y la red....................................................................... 36 III.2.1.1.1 Creación de enrutadores y redes..................................................... 36 III.2.1.1.2 Obtención de información.............................................................. 37 III.2.1.1.3 Inicio, pausa y parada de la ejecución............................................ 37 III.2.1.2 Con las gráficas..................................................................................... 37 III.2.1.2.1 Despliegue de las gráficas.............................................................. 37 III.2.1.2.2 Actualización de las gráficas.......................................................... 37 III.2.2 De los enrutadores........................................................................................ 37 III.2.2.1 Con la visualización.............................................................................. 38 III.2.2.2 Con la red............................................................................................... 38 III.2.2.2.1 Solicitud de información................................................................. 38 III.2.2.2.2 Envío de paquetes........................................................................... 38 III.2.2.3 Con los paquetes.................................................................................... 38 III.2.2.3.1 Envío............................................................................................... 38 III.2.2.3.2 Corrección de errores...................................................................... 39 v III.2.2.4 Con los Algoritmos................................................................................ 39 III.3.1 Especificación en TDSO............................................................................... 39 III.3.1.1 Clase Componente................................................................................. 40 III.3.1.2 Clase Algoritmo..................................................................................... 45 III.3.1.3 Clase Enrutador..................................................................................... 46 III.3.1.3.1 Carga de los algoritmos de enrutamiento....................................... 47 III.3.1.3.2 Especificación en TDSO del algoritmo de envío de paquetes....... 48 III.3.1.4 Especificación en TDSO de la clase paquete........................................ 49 III.3.1.5 Especificación en TDSO de la clase red............................................... 51 III.3.1.5 Especificación en TDSO de la clase visualización................................ 52 vi Capítulo IV: Implementación y pruebas IV.1 Clase componente................................................................................................ 55 IV.1.1 El manejo de eventos.................................................................................... 55 IV.1.2 El funcionamiento de los hilos..................................................................... 59 IV.2 Clase algoritmo.................................................................................................... 60 IV.2.1 Los eventos................................................................................................... 60 IV.3 La visualización................................................................................................... 63 IV.3.1 Errores de Interacción con el usuario........................................................... 67 IV.3.1.1 Error de asignación de IP...................................................................... 67 IV.3.1.2 Error enlazando un enrutador................................................................ 67 Capítulo V: Conclusiones y recomendaciones V.1 Recomendaciones................................................................................................. 71 Bibliografía.................................................................................................................. 72 Anexos Anexo #1. Clase red..................................................................................................... 73 Anexo #2. Clase Componente..................................................................................... 80 Anexo #3. Clase Enrutador......................................................................................... 87 Anexo #4. Clase Class Loaded............................................................................…… 93 Anexo #5. Clase Algoritmo......................................................................................... 95 Anexo #6. Clase Paquete............................................................................................. 99 Anexo #7. Clase Simulación........................................................................................ 105 vii Indice de Figuras. Figura Pág. 2-1 Enrutamiento..................................................................................................................... 7 2-2 Saltos de Routers.............................................................................................................. 9 2-3 QoS................................................................................................................................... 20 3-1 Conexión de las Entidades................................................................................................ 36 3-2 Visualización de la conexión de las entidades................................................................. 36 3-3 Arbol de Herencia de las clases....................................................................................... 39 3-4 Arbol de Herencia de las clase componente, enrutador, red............................................ 40 3-5 Arbol de Herencia de la clase Visualización..................................................................... 40 4-1 Visualización del menú del componente........................................................................... 56 4-2 Imagen del menú de configuración de la clase estático..................................................... 62 4-3 Imagen de la visualización una vez creada........................................................................ 66 4-4 Imagen de la visualización ejecutándose........................................................................... 66 4-5 Imagen de un error de asignación de IP............................................................................ 68 viii RESUMEN. El incremento de las redes hoy en día, se ha traducido en una mayor cantidad de tráfico de paquetes, por lo tanto, es necesario encontrar una forma eficiente de canalizar este tráfico, para lograr un mejor funcionamiento de las mismas. Este trabajo consiste en establecer una plataforma de visualización que sirva para enseñar a los administradores de redes los mecanismos de enrutamiento existentes. Para realizar este trabajo, se dividió el proyecto en cinco fases. Primera Fase: Análisis del problema y metodología a usar. Segunda Fase: Revisión bibliográfica. Tercera Fase: Selección de la plataforma de desarrollo, sistema operativo a usar, del API e implementación teórica del programa. Cuarta Fase: Implementación del programa y pruebas. Quinta Fase: Análisis de las pruebas realizadas, recomendaciones y conclusiones. i Descriptores: - Redes de Computadoras. Cota: TK51055C38 ii Capítulo I: Introducción. Hoy en día la comunicación por computadoras se ha hecho parte esencial de nuestra vida, están presentes en todos los aspectos de los negocios: publicidad, producción, planeamiento, facturación y contabilidad, por lo tanto la mayoría de las corporaciones basan su infraestructura de trabajo en redes. Son una herramienta fundamental del proceso educativo, desde la escuela primaria hasta los postgrados. Las redes están presentes en todos lados. Este aumento creciente en las redes implica un mayor tráfico en las mismas, por lo cual se hace necesario un manejo óptimo para garantizar el mejor desempeño de las comunicaciones. Esto implica más eficiencia en el trabajo de los administradores de redes como tales, poniendo en práctica técnicas de enrutamiento que puedan probar y verificar antes de hacer una implementación costosa. I.1 Problema Planteado. El tráfico creciente en Internet, nos crea la necesidad de buscar mejores formas de canalizarlo, para que sea lo más fluido posible. Para ello, los administradores (aquellos que se encargan de monitorear las redes), deben tener herramientas que les permitan desarrollar criterios para escoger los caminos más apropiados que detecten y resuelvan las fallas que se puedan presentar. Por lo tanto, el diseño de una herramienta que permita visualizar las distintas técnicas de enrutamiento es fundamental. 1 I.2 Objetivos Generales. Diseñar una herramienta que permita visualizar las distintas técnicas de enrutamiento de paquetes en una o varias redes. I.2.1 Objetivos Específicos. • Afianzar los conocimientos en programación JAVA. • Permitir el estudio de diferentes protocolos de enrutamiento. • Desarrollar aplicaciones SWING para JAVA. I.3 Metodología. I.3.1 Fase I: Revisión bibliográfica de los algoritmos de enrutamiento. Se estudiaron los diferentes tipos de enrutamiento para obtener los rasgos generales de estos, también se revisó la información sobre enrutadores y redes que se llamaran “entidades”. Todo esto con el fin de tener una primera impresión sobre los distintos algoritmos que debían seguir cada uno de ellos, y plantear los requisitos que debía tener la plataforma de desarrollo. I.3.2 Fase II: Selección de la plataforma de desarrollo. Se plantearon los requisitos que debía cumplir la plataforma de trabajo, lo que permitió una visión más precisa para escoger el compilador más apropiado. Los requisitos son: • El lenguaje de desarrollo debe ser orientado a objetos, ya que esto facilita en gran medida la abstracción de las “entidades” que componen la visualización. 2 • Debe permitir la ejecución de “Threads” (Hilos), así no hay retraso en la comunicación entre las “entidades”, además de que estas también deben ejecutarse en forma concurrente para llevar a cabo sus propios cálculos. • Las capacidades gráficas también deberían ser de fácil desarrollo, pues se necesita representar gráficamente a las “entidades”, y una interfaz gráfica de usuario es más fácil de usar que una interfaz de usuario en modo texto. • Debe permitir la ejecución de temporizadores para asignarle “Tareas” a las “entidades”. Un ejemplo de esto son las redes, que deben generar paquetes cada cierto tiempo para que estos sean procesados por los enrutadores. Las plataformas que cumplieron con los requisitos planteados fueron C++ para Linux y Java, de estas dos plataformas de desarrollo se escogió Java, que tiene la ventaja de ejecutarse en múltiples plataformas. I.3.3 Fase III: Selección del Sistema Operativo. Una vez seleccionada la plataforma de desarrollo se procedió a probarla en los diferentes sistemas operativos (Windows, Linux), como sistema operativo se escogió Linux debido a las utilidades que presta para el desarrollo. I.3.4 Fase IV: Selección de un API para el desarrollo de la GUI. Existen dos interfaces de desarrollo de aplicaciones gráficas en Java, AWT y JFC/Swing. La gran diferencia entre los componentes AWT y los Swing es que estos últimos, fueron implementados sin partes en código nativo. Por esto sus características están presentes en todas las plataformas, además tiene mayor cantidad de funcionalidades, por estas razones se escogió JFC/Swing como el API para desarrollo gráfico. 3 I.3.5 Fase V: Revisión bibliográfica del API Swing. Se investigó sobre la forma de desarrollo con el API JFC/Swing, y se descargaron de la red diferentes tutoriales disponibles vía Internet para iniciarnos en el desarrollo con JFC/Swing. I.3.6 Fase VI: Prueba de aplicaciones JFC/Swing. Se desarrollaron algunas aplicaciones para probar las características de JFC/Swing. Entre las características que se probaron están los JFrames (Ventanas), JButton (Botones), JList (Listas de selección), Jpanel (Paneles) y otras más. También se probaron las diferentes aplicaciones que trae el JDK como ejemplos, para ver como interactúan los diferentes componentes entre ellos. I.3.7 Fase VII: Prueba de los “Threads” en Java. Se crearon algunos programas para probar las diferentes formas de ejecutar “Threads” en Java. Entre los diferentes métodos encontrados están la clase “Thread” y la Interfaz “Runnable”, se optó por utilizar la interfaz, ya que los “Threads” presentan algunos problemas con los métodos stop y suspend (métodos que en JAVA están deprecados), muy necesarios para controlar el estado de ejecución de las “entidades”. I.3.8 Fase VIII: Diseño de las clases. En principio se decidió dividir en capas la aplicación, estas capas comprendían: la capa de visualización y la capa de ejecución. Cada “entidad” de la simulación tenía su representación en ambas capas, es decir, la red comprendía tanto la Red de ejecución como la Red de visualización. Pero este enfoque presentaba algunos problemas. Por esto se decidió desarrollar en una sola capa, es decir las clases contienen tanto la implementación de ejecución como la de visualización, así cualquier cambio que se realizase sobre alguna de las clases se reflejaría inmediatamente sobre la interfaz gráfica. 4 I.3.9 Fase IX: Implementación de la capa de ejecución. Se desarrolló la clase abstracta Componente con los métodos que debían ser implementados por las clases, que también serviría como apoyo a la hora de contener a las “entidades” y lograr así llamar a los métodos generales sin necesidad de saber a que clase de objeto nos estamos refiriendo. Luego se desarrolló la interfaz Algoritmo que debe ser implementada por las diferentes clases de algoritmos de enrutamiento. Esta interfaz contiene algunos métodos generales utilizados por los algoritmos de enrutamiento, otra utilidad que tiene es que la clase enrutador puede utilizar diferentes algoritmos de enrutamiento refiriéndose solamente a los métodos generales contenidos en esta interfaz. Una vez implementadas ambas interfaces, se procedió a desarrollar la clase Enrutador, un temporizador se encarga de procesar los paquetes cada vez que se cumple un tiempo de retardo, además, éste contiene una lista donde se almacenan las redes a las que este enrutador está conectado con sus respectivas direcciones IP. La clase Red también tiene un temporizador, pero esta vez el temporizador se usa para generar paquetes periódicamente, la Red se ejecuta también como un hilo procesando los paquetes que pasan a través de ella. 5 Capítulo II: Marco Teórico. II.1 Enrutamiento. El enrutamiento es una de las funciones principales de la capa red, consiste en trasladar paquetes desde una máquina origen a una máquina destino. A lo largo del camino, en general, se encuentra al menos un nodo intermedio. Podemos definir enrutamiento como un proceso mediante el cual tratamos de encontrar un camino entre dos puntos de la red: el nodo origen y el nodo destino. En esta definición tenemos que matizar el hecho de que cuando hablamos de un camino nos estamos refiriendo a varios, el mejor total o el mejor para llegar de 1 a N puntos. Habría que tener en cuenta también la capilaridad de las redes (conexión de los nodos con los terminales de usuario), por lo que no se trataría de buscar un camino entre dos nodos, sino entre dos terminales. En realidad, resolviendo lo primero se resuelve lo segundo, y se enunciara el problema como la búsqueda de un camino de conexión entre dos nodos de la red. En su viaje entre ambos host los paquetes han de atravesar un número indefinidos de host o dispositivos de red intermedios, debiendo existir algún mecanismo capaz de direccionar los paquetes correctamente de uno a otro nodo hasta alcanzar el destino final. Este mecanismo de enrutamiento es responsabilidad del protocolo IP, y lo hace de tal forma que los protocolos de las capas superiores, como TCP y UDP, no tienen constancia alguna del mismo, limitándose a preocuparse de sus respectivas tareas. Cuando un host debe enviar datos a otro, lo primero que hace es comprobar si la dirección IP de éste se encuentra en su tabla de rutas interna, en cuyo caso los datagramas le son enviados directamente mediante la dirección de su tarjeta de red, conocida como dirección física. En caso de que no conozca la misma, envía un mensaje de petición, que será respondido por el host destino enviando su dirección física, con la que ya tiene los datos suficientes para la transmisión de las tramas. Este proceso recibe el nombre de entrega directa. En caso de que el remitente no encuentre en su red interna la red necesaria, los datagramas son enviados a un dispositivo especial, denominado router o gateway (pasarela), que se encarga de 6 buscar la ruta de direccionamiento que se deben dar a los datagramas para que alcancen su destino correcto Se puede decir que un router es un dispositivo conectado a dos o más redes, perteneciendo a todas ellas a la vez, por lo que tendrá una dirección física y una dirección IP diferente en cada una de las mismas, tal como puede verse en la siguiente figura, de dos redes unidas por un router: Figura 2-1. Enrutamiento. Ejemplo: Si el host B de la red A desea enviar un paquete al host H, lo primero que hará será comprobar si el host de destino aparece en su tabla interna, y si no es así, no pertenece a A. Como H no puede responder a la misma, al estar en otra red, B decidirá enviar los paquetes al router para que éste se encargue de su direccionamiento. Los paquetes que le pasa contienen la dirección IP de H y la dirección física del router. Los routers poseen unas tablas de enrutamiento en las que almacenan información sobre el mejor camino que pueden seguir los paquetes para llegar a su destino. Cuando le llegan los paquetes, el router debe extraer de ellos la dirección de la red a la que pertenece H, para saber a cuál de las redes que une debe mandar los paquetes. Para ello, toma la dirección IP de destino y realiza con ella y las máscaras de red de cada una de las redes a las que pertenece una operación AND lógica, con lo que obtendrá la dirección de la red destino. Para realizar la operación AND pasa las direcciones IP a formato binario: 7 host H: 220.2.110.0 = 11011100.00000010.01101110.00001010 máscara de red: 255.255.255.0 = 11111111.11111111.11111111.00000000 Resultado de operación AND: 11011100.00000010.01101110.0000000000 = 220.2.110.0 Con esto, el router sabe que debe enviar los paquetes a la red B, de dirección de red 220.2.110.0. Entonces, actuando como un host más de la misma, consulta su tabla, obtiene la dirección de tarjeta de H y le envía directamente los paquetes. Si no encuentra la tabla de dirección de H realizará una petición, con lo que éste le enviará su dirección física, completándose la entrega. De todo esto se desprende que si sólo tuviéramos que enviar datos entre host de la misma red no sería necesario el uso del protocolo IP, ya que con el direccionamiento físico mediante los números de las tarjetas de red se podría trabajar perfectamente. Pero en cuanto se deben mandar datos a host de otra red el protocolo IP se hace necesario, ya que sólo con el número de tarjeta del host destino no se podrían enviar los datos. La causa de esto es que el conjunto de números de tarjeta de red conforma un sistema de direccionamiento plano, ya que dichos números son asignados secuencialmente por el fabricante de la tarjeta, no dando información alguna de la localización del host que tiene instalada la tarjeta. En cambio, el sistema de direcciones IP es un sistema de direccionamiento jerárquico, puesto que las IP se asignan mediante unas reglas específicas que hacen posible la rápida localización de la red y del host al que van dirigidos los paquetes. Si se continúa complicando el ejemplo anterior, se puede considerar el caso en que el router, al realizar las operaciones AND lógicas, compruebe que el host destino no pertenece a ninguna de las redes que conecta. En este caso mirará en sus tablas de ruteo internas para ver a dónde debe mandar los paquetes, destino que generalmente será otro router. Se produce una serie 8 de saltos en los que los paquetes van siendo enviados a sucesivos routers, hasta llegar a uno de ellos que sí está conectado a la red destino, y que será el que entregue los paquetes. Figura 2-2.Saltos de Routers. Cada uno de los sucesivos routers que atraviesa la trama en su camino extrae la dirección física de la misma y la sustituye por la suya propia, dejando constante la dirección IP destino. Y esto sucede así hasta el último router, al que pertenece la red del host destino y hace la entrega final de la trama. Esto es lo que ocurre en Internet, donde los saltos entre routers se realizan por medio de sistemas de cableado telefónico, por satélite, etc., con objeto de poder hacer llegar los paquetes a su destino lo antes posible. En el caso de que en la red del host origen haya varios routers puede darse el caso de que el paquete sea enviado al router equivocado. En estos casos el paquete no será enviado correctamente, entrando en escena el protocolo IP, que notificará el error al host remitente, informándole de la ruta correcta a usar. Entonces éste envía los paquetes al router adecuado, actualizando de paso su propia tabla de ruteo, con lo que en envíos sucesivos al mismo destino los paquetes serán enviados directamente a ese router. 9 El objetivo que se persigue es encontrar las mejores rutas entre pares de nodos. Para ello se establecerá lo que se entiende por mejor ruta y la métrica que se emplea para determinarla.: a) Mejor Ruta. Por mejor ruta se entiende aquella que cumple alguna de estas condiciones: • Presenta el menor retardo medio de transito. • Consigue mantener acotado el retardo entre pares de nodos de la red. • Consigue ofrecer altas cadencias efectivas independientemente del retardo medio de transito • Ofrece el menor costo. b) Métrica de la Red. Citaremos dos de ellas: Numero de saltos (canales) necesarios para ir de un nodo a otro. No se comporta de forma óptima, pero si ofrece buenos resultados, y es empleada con bastante frecuencia.. La distancia (valor que se asocia a cada canal) es igual a 1 para todos los canales. Retardo de Transito entre nodos vecinos. En este caso la distancia se expresa en unidades de tiempo, y no es constante a lo largo del tiempo sino que depende del trafico que soporta el canal. Se estudiará las redes de conmutación de paquetes, tanto en modo datagrama como en modo circuito virtual. b.1) Red en modo circuito virtual. Si la red funciona en modo circuito virtual generalmente se establece una ruta que no cambia durante el tiempo de vida de ese circuito virtual, ya que esto es lo más sencillo para preservar el orden de los paquetes. El enrutamiento se decide por sesión y no se cambia a menos que sea imprescindible, es decir existen restricciones de capa a no cambiar el enrutamiento en la sesión (ej. caída de un enlace). Cuando eso ocurre se busca inmediatamente otra ruta, pero este cambio al tardar en propagarse por la red y al tardar los nodos en enterarse, puede afectar los sistemas finales 10 de tres formas: • no se manifiesta • se pierde información • se pierde la sesión. b.2) Red en modo datagrama Como en este caso no debe garantizarse el ordenamiento final de los paquetes, en una red funcionando en modo datagrama se puede cambiar el criterio de enrutamiento por cada paquete que se ha de cursar (Esto da origen a menor número de problemas). El problema no es simple, como puede parecer a simple vista, para redes reales, puesto que hay que tener en cuenta los cambios de carga de los enlaces y los cambios de configuración (debidos a altas y bajas, a averías en los nodos, etc.). Llegados a este punto conviene decir que el enrutamiento busca el camino óptimo, pero como el tráfico varía con el tiempo, el camino óptimo también dependerá del instante en que se observa la red. Los protocolos serán los encargados de ocultar la red y comprobar que las condiciones impuestas se verifican siempre. Por esta razón, el enrutamiento debe proveer a la red de mecanismos para que ésta sepa reaccionar ante situaciones como: • Variabilidad del tráfico: se han de evitar las congestiones de la red. • Variaciones topológicas, como las mencionadas arriba: caídas de enlaces, caídas de nodos, altas y bajas ... • Cambios en la QoS (Quality of Service): a veces se pide un servicio donde no importa el retardo y sí un alto throughput, y viceversa. Se tiene entonces un sistema distribuido, donde cada nodo debe tener una cierta inteligencia y se produce un procesamiento independiente de cada nodo (no hay proceso central). También es un sistema asíncrono, en el sentido de que no hay un momento determinado para que ocurran las cosas (un nodo transmite cuando le llega información, y esto sucede a 11 su vez cuando el usuario decide mandarla). El enrutamiento implica dos actividades básicas: la determinación de las trayectorias óptimas de enrutamiento y el transporte de los grupos de información como tal (llamados paquetes) a través de la red. El transporte de los paquetes es relativamente directo, la trayectoria es donde entran los algoritmos de enrutamiento, los cuales son la parte del software de la capa de red encargada de decidir la línea de salida por la que se transmitirá un paquete de entrada. Para facilitar el proceso de determinación de la trayectoria, los algoritmos de enrutamiento inicializan y conservan tablas de enrutamiento, que contienen información acerca de todas las rutas. Esta información varia dependiendo del algoritmo de enrutamiento que se utilice. Los algoritmos de enrutamiento alimentan las tablas de enrutamiento con una gran variedad de información. Las asociaciones de salto destino-próximo informan al enrutador que se puede llegar al destino particular de manera óptima enviando el paquete a otro enrutador particular que represente el “próximo salto” en el camino a su destino final. Generalmente, los algoritmos de enrutamiento se diseñan con uno o más de estos objetivos: 1. Que sea un diseño óptimo. 2. Que sea sencillo y con la menor cantidad posible de material inútil. 3. Que sea robusto y estable. 4. Que permita una convergencia rápida. 5. Que sea flexible. El diseño óptimo se refiere a la capacidad de un algoritmo de enrutamiento de seleccionar la mejor ruta, lo cual depende de las medidas y del peso que se asigne a dichas medidas para realizar el cálculo. Deben estar diseñados para que sean lo mas simple posible, es decir, debe ofrecer su funcionalidad de una manera eficiente, con un mínimo de software y utilización óptima. La eficiencia es particularmente importante cuando el software del algoritmo de enrutamiento deba correr sobre una computadora con recursos físicos limitados. 12 Deben ser robustos, lo que significa que deben desempeñarse correctamente aun cuando se enfrenten a circunstancias poco comunes e imprevistas, tales como fallas del hardware, condiciones de carga alta e implementaciones incorrectas. Debido a que los enrutadores se encuentran en los puntos de unión de la red, pueden causar problemas considerables cuando llegan a fallar. Los mejores algoritmos de enrutamiento son aquellos que han resistido la prueba del tiempo y han demostrado que permanecen estables en una gran variedad de condiciones de la red. Los algoritmos de enrutamiento deben converger rápidamente, proceso por el cual todos los enrutadores llegan a un acuerdo con respecto a las rutas óptimas. Los algoritmos de enrutamiento que convergen con lentitud, pueden provocar ciclos de enrutamiento infinitos o tiempos muertos en la red. Los algoritmos de enrutamiento han utilizado muchas y diferentes métricas para determinar cual es la mejor ruta. Los algoritmos más sofisticados pueden basar la selección de rutas en múltiples medidas y combinarlas en una sola medida (híbrida). En tal sentido tenemos las siguientes medidas: • Longitud de la trayectoria. • Confiabilidad. • Retardo. • Ancho de Banda. • Carga. • Costo de Comunicación. La longitud de la trayectoria es la medida de enrutamiento más común. Algunos protocolos de enrutamiento permiten que los administradores de red asignen costos arbitrarios a cada uno de los enlaces de la red. En este caso, la longitud de la trayectoria es la suma de los costos asociados con cada uno de los enlaces por los que se pasa. Otros protocolos de enrutamiento definen un conteo de saltos, una medida que especifica el número de veces que un paquete pasa a través de los productos que conforman la red, por ejemplo enrutadores, en su trayecto de origen a destino. La confiabilidad en el contexto de enrutamiento, se refiere a la dependencia de cada enlace de la 13 red. Algunos enlaces de red pueden caerse con mayor frecuencia que otros. Cuando falla una red, algunos enlaces en la red pueden repararse más fácil o rápidamente que otros. Cualquier factor de confiabilidad puede tomarse en cuenta en la determinación del valor de la misma, ya que son valores numéricos arbitrarios asignados generalmente a los enlaces de red por los administradores del sistema. El retardo de enrutamiento se refiere al periodo de tiempo que se requiere para transferir de origen a destino a través de la red. Depende de muchos factores, entre los cuales se encuentra el ancho de banda de los enlaces intermedios de la red, las colas en los puertos de cada enrutador a lo largo del camino, la saturación de la red en todos sus enlaces intermedios y la distancia física a recorrer. Como el retardo es un conglomerado de algunas variables importantes, es una medida muy común y útil a la vez. El ancho de banda se refiere a la capacidad de tráfico disponible de un enlace. Aunque el ancho de banda es una medida del rendimiento eficiente total máximo que se puede alcanzar en un enlace, las rutas que pasan a través de enlaces con un ancho de banda mayor no necesariamente son mejores rutas que las que viajan a través de enlaces más lentos. Por ejemplo, si un enlace rápido esta muy ocupado, puede requerir más tiempo para enviar un paquete a su destino. La carga se refiere a qué tan ocupado está un recurso de la red, como un enrutador por ejemplo . La carga se puede calcular de muchas maneras, entre otras, la utilización del CPU y el número de paquetes procesados por segundo. La supervisión continua de estos parámetros puede consumir por si misma muchos recursos. Los costos de comunicación son otra medida importante, sobre todo porque a algunas compañías no les importa tanto el desempeño de una red como los costos de operación de la misma. A pesar de que el retardo de la misma puede ser más grande, enviarán paquetes a través de sus propias líneas en vez de hacerlo por líneas públicas, las cuales tienen un costo asociado en función del tiempo de uso. Cuando un enrutador recibe un paquete entrante, verifica la dirección de destino e intenta asociar esta dirección con el siguiente salto. 14 Las tablas de enrutamiento también pueden contener otra información, como son los datos acerca de la conveniencia de una trayectoria. Los enrutadores comparan medidas para determinar rutas optimas y estas medidas difieren en función del diseño del algoritmo de enrutamiento que se utilice. Los enrutadores se comunican entre si y conservan sus tablas de enrutamiento a través del envío de una gran variedad de mensajes, entre ellos el mensaje de actualización, formado por una tabla de enrutamiento en general o una porción de la misma. Al analizar las actualizaciones de enrutamiento de todos los demás enrutadores, un enrutador puede hacerse una idea detallada de la topología de la red. Cuando un evento en la red provoca que las redes se caigan o no estén disponibles, los enrutadores distribuyen mensajes de actualización de enrutamiento que penetra en las redes, estimulando el recálculo de las rutas óptimas y, ocasionalmente, haciendo que todos los enrutadores lleguen a un acuerdo respecto a esas rutas. Otro tipo de mensaje es el anuncio del estado del enlace, el cual informa a los demás enrutadores acerca del estado de los enlaces del emisor, esta información puede utilizarse también para hacerse una idea completa de la topología de la red, lo que les permite determinar las rutas óptimas hacia los destinos de la red. En el cálculo de las tablas de enrutamiento, aunque el cálculo manual es suficiente para ejemplos sencillos, tales métodos son imprácticos en las redes grandes; por lo tanto se utiliza software para calcular estas tablas; existen dos métodos básicos: Enrutamiento Estático: Un programa calcula e instala las rutas al arrancar el conmutador de paquetes; las rutas se mantienen constantes. Sus algoritmos son no adaptables, es decir, no basan sus decisiones de enrutamiento en mediciones o estimaciones de tráfico y la topología actuales. Las tablas de enrutamiento de los nodos se configuran de forma manual y permanecen inalterables hasta que no se vuelve a actuar sobre ellas. La adaptación a cambios es nula. Tanto la recogida como la distribución de información se realiza por gestión (se realiza de manera externa a la red), sin ocupar capacidad de red. El calculo de ruta se realiza off-line (en una maquina especifica),y las 15 rutas pueden ser las optimas al no estar sometido al requisito de tiempo real. Este tipo de enrutamiento es el optimo para topologías en los que solo hay una posibilidad de enrutamiento (topología en estrella). Enrutamiento Cuasiestático: Este enrutamiento, es igual que el estático pero en vez de dar una sola ruta fija, se dan además varias alternativas en caso de que la principal no funcione, de ahí que tenga una adaptabilidad reducida. Este tipo de enrutamiento puede dar lugar a situaciones incoherentes, ya que no se enteran todos los nodos de los problemas de la red, sino sólo los adyacentes a los problemas. Enrutamiento Dinámico: Un programa construye una tabla inicial de enrutamiento al arrancar el conmutador de paquetes; entonces, el programa modifica la tabla a medida que cambian las condiciones de la red. Sus algoritmos son adaptables, cambian sus decisiones de enrutamiento para reflejar los cambios en la topología, y generalmente también el tráfico. Cada uno de ellos tiene sus ventajas y desventajas. Las ventajas principales del enrutamiento estático son su simplicidad y su baja sobrecarga en la red, su desventaja principal es la inflexibilidad (las rutas estáticas no pueden cambiarse con facilidad) . La mayor parte de las redes acuden al enrutamiento dinámico porque permite que la red maneje automáticamente los problemas. Por ejemplo, mediante programas se puede supervisar el tráfico de la red, así como el estado del hardware de red. Los programas modifican sus rutas para adaptarse a las fallas. Debido a que las redes grandes se diseñan con conexiones redundantes para el manejo de fallas ocasionales del hardware, la mayor parte de las redes grandes usa una forma de enrutamiento dinámico. Los algoritmos de enrutamiento estáticos no se pueden considerar verdaderos algoritmos, sino que son mapeos de tablas que el administrador de la red establece antes de empezar el enrutamiento, los cuales no varían a menos que sean modificadas por el administrador. Los algoritmos estáticos son de fácil diseño y funcionan bien en entornos donde el tráfico en la red es hasta cierto punto predecible y el diseño de la red es relativamente simple. Como los sistemas de enrutamiento estáticos no pueden reaccionar ante los cambios de la red, por lo general no se les 16 considera idóneos a ser usados en las redes actuales, ya que estas cambian constantemente. En la actualidad, la mayor parte de los algoritmos de enrutamiento que se han impuesto son dinámicos, por su adaptabilidad a situaciones cambiantes en la red. Los algoritmos de enrutamiento dinámicos se pueden complementar con rutas estáticas cuando sea conveniente II.2 Tipos de Enrutamiento. II.2.1 Estáticos. II.2.1.1 Enrutamiento por la Trayectoria más Corta. Su idea se basa en la construcción de un grafo de la subred, en el que cada nodo representa un enrutador y cada arco del grafo, una línea de comunicación. Para escoger una ruta entre un par dado de enrutadores, el algoritmo simplemente encuentra en el grafo la trayectoria más corta entre ellos. Uno de los algoritmos más conocidos en estos casos es el algoritmo de Dijkstra (1959). Cada nodo se etiqueta con su distancia al nodo de origen a través de la mejor trayectoria conocida. Inicialmente no se conocen trayectorias, por lo que todos los nodos tienen la etiqueta infinito. A medida que avanza el algoritmo y se encuentran trayectorias, pueden cambiar las etiquetas, reflejando mejores trayectorias. Una etiqueta puede ser tentativa o permanente. Inicialmente todas las etiquetas son tentativas. Al descubrirse que una etiqueta representa la trayectoria más corta posible del origen a ese nodo, se vuelve permanente y no cambia más. II.2.1.2 Inundación. Consiste en enviar cada paquete de entrada por cada una de las líneas de salida, excepto aquella por la que llegó. Evidentemente genera gran cantidad de paquetes duplicados; de hecho, una cantidad infinita a menos que se tomen medidas para limitar el proceso. Una de tales medidas es un contador de escalas contenido en la cabecera de cada paquete, el cual disminuye en cada escala, descartándose el paquete al llegar el contador a cero. Idealmente, el contador de escalas debe inicializarse con la longitud de la trayectoria del origen a destino. Si el transmisor no conoce el tamaño de la trayectoria, inicializa el contador al peor caso, es decir, la longitud total de la subred. II.2.1.3 Enrutamiento Basado en Flujo. 17 A diferencia de la mayoría de los algoritmos estáticos, los cuales sólo toman en cuenta la topología, estos consideran la carga. Por ejemplo, si existe una gran cantidad de tráfico en un tramo, podría ser mejor redireccionar ese trafico por una ruta alterna aunque parezca más larga. En algunas redes, la tasa media de flujo de datos entre cada par de nodos es relativamente estable y predecible. La idea en que se basa el análisis es que, para una línea dada, si se conocen la capacidad y el flujo promedio, es posible calcular el retardo promedio de los paquetes en esa línea a partir de la teoría de colas. II.2.2 Dinámicos. II.2.2.1 Enrutamiento por Vector de Distancia. Estos algoritmos operan haciendo que cada enrutador mantenga una tabla que da la mejor distancia conocida a cada destino y la línea a usar para llegar allí. Estas tablas se actualizan intercambiando información con los vecinos. Este algoritmo recibe otros nombre, como algoritmo de enrutamiento Bellman-Ford distribuido y el de algoritmo Ford-Fulkerson. En este tipo de enrutamiento, cada enrutador mantiene una tabla de enrutamiento indizada por, y conteniendo un registro de, cada enrutador. Esta entrada comprende dos partes: la línea preferida de salida hacia ese destino y una estimación del tiempo o distancia a ese destino. II.2.2.2 Enrutamiento por Estado de Enlace. El basamento de este tipo de enrutamiento es sencillo, consiste en cinco partes en las que cada enrutador debe: • Descubrir a sus vecinos y conocer sus direcciones de red. • Medir el retardo o costo para cada uno de sus vecinos. • Construir un paquete que indique todo lo que acaba de aprender. • Enviar este paquete a todos los demás enrutadores. • Calcular la trayectoria más corta a todos los demás enrutadores. De hecho, la topología total y todos los retardos se miden experimentalmente y se distribuyen a 18 cada enrutador. Entonces puede usarse el algoritmo de Dijkstra (1959) para encontrar la trayectoria más corta a todos los demás enrutadores. II.2.2.3 Enrutamiento Jerárquico. A medida que crecen en tamaño las redes, crecen proporcionalmente las tablas de enrutamiento del enrutador. Las tablas que siempre crecen no sólo consumen memoria del enrutador, sino que también se necesita más tiempo CPU para examinarlas y más ancho de banda para enviar informes de estado de enrutadores. En cierto momento, la red puede crecer hasta el punto en que ya no es factible que cada enrutador tenga una entrada para cada uno de los demás enrutadores, por lo que el enrutamiento tendrá que hacerse jerárquico. En el enrutamiento jerárquico, los enrutadores se dividen en regiones, donde cada enrutador conoce todos los detalles de la manera de enrutar paquetes a destinos dentro de su propia región, pero no sabe nada de la estructura interna de las otras regiones, de esta forma se liberan los enrutadores de una red de la necesidad de conocer la estructura topológica de las demás redes. II.2.2.4 Enrutamiento por Difusión. En algunas situaciones, es necesario para los hosts enviar mensajes a varios otros hosts o a todos los demás. El envío simultáneo de un paquete a todos los destinos se llama difusión. Utilizando el método de enrutamiento multidestino, cada paquete contiene una lista de destinos o un mapa de bits que indica los destinos deseados. Al llegar un paquete al enrutador, este revisa todos los destinos para determinar el grupo de líneas de salida que necesitará. El enrutador genera una copia nueva del paquete para cada línea de salida a usar, e incluye en cada paquete sólo aquellos destinos que usan la línea. Cada paquete llevará sólo un destino, así que puede tratarse como un paquete normal. Otro método utilizado es el árbol de extensión, el cual es un subgrupo de la subred que incluye todos los enrutadores, pero no contiene ciclos. Si cada enrutador sabe cuáles de sus líneas pertenecen al árbol de extensión, puede copiar un paquete de entrada difundido en todas las líneas del árbol de extensión, excepto en aquella por la que llegó. Este método hace un uso excelente del ancho de banda, generando la cantidad mínima de paquetes necesarios para llevar a 19 cabo el trabajo. II.2.2.5 Enrutamiento por Multitransmisión. Para la Multitransmisión se requiere administración de grupos. Se necesita alguna manera de crear y destruir grupos, y un mecanismo para que los procesos se unan a los grupos y salgan de ellos. La forma de realizar esta tarea no le concierne al algoritmo de enrutamiento, lo que si le concierne es que, cuando un proceso se una a un grupo, informe a su host del hecho. Es importante que los enrutadores sepan cuáles de sus hosts pertenecen a qué grupos. Los hosts deben informar a los enrutadores de los cambios en los miembros del grupo, o los enrutadores deben enviar periódicamente la lista de sus hosts. Para hacer el enrutamiento de Multitransmisión, cada enrutador calcula un árbol de extensión que cubre a todos los demás enrutadores de la subred. II.2.2.6 Calidad de Servicio (QoS – Quality of Service). La calidad de Servicio (QoS, Quality of Service) define un conjunto de atributos relacionados con el rendimiento de la conexión. Para cada conexión, el usuario puede solicitar un atributo concreto. Cada clase de servicio esta asociada con un conjunto de atributos. Los atributos se pueden clasificar en atributos que están relacionados con el usuario y en atributos relacionados con la red La siguiente figura muestra las dos categorías y algunos atributos importantes de cada categoría: Figura 2-3. QoS 20 II.2.2.6.1 Atributos relacionados con el usuario. Son aquellos atributos que definen la velocidad con la que el usuario quiere enviar los datos. Estos atributos se negocian cuando se realiza el contrato entre un usuario y una red. A continuación se describen algunos atributos relacionados con el usuario. • Tasa de Celdas Sostenida (SCR, Sustained Cell Rate), es la tasa de celdas media en un intervalo de tiempo largo. La tasa de celdas real puede ser mayor o menor, pero la media debería ser igual o menor que la SCR. • Tasa de Celdas Pico (PCR, Peak Cell Rate), define la máxima tasa de celdas del emisor. La tasa de celdas del usuario, puede alcanzar en algunas ocasiones este pico, mientras que se mantenga la SCR. • Tasa de Celdas Mínima (MCR, Minimum Cell Rate), define la tasa de celdas mínima aceptable para el emisor. Por ejemplo, si la MCR es 50000, la red debe garantizar que el emisor puede enviar el menos 50000 celdas por segundo. • Tolerancia en el Retardo a la Variación de Celdas (CVDT, Cell Variation Delay Tolerance), es una medida de variación en los instantes de transmisión de celdas. Por ejemplo, si la CVDT es de 5 nanosegundos, entonces la diferencia entre los retardos mínimos y máximos en la entrega de celdas no debería exceder los 5 nanosegundos. II.2.2.6.2 Atributos Relacionados con la Red. Son los que definen las características de la red. A continuación se definen algunos de estos atributos: • Tasa de Celdas Perdidas (CLR, Cell Loss Ratio), define la fracción de celdas perdidas (o entregadas demasiado tarde y que se consideran perdidas) durante la 21 transmisión. Por ejemplo, si el emisor envia 100 celdas y una se pierde, la CLR es CLR=1/100=10-2 . • Retardo en la Transferencia de Celdas (CTD, Cell Transfer Delay), es el tiempo medio necesario para que una celda viaje de origen a destino. También se consideran como atributos al CTD máximo y al CTD mínimo. • Variación en el Retardo de Celdas (CDV, Cell Delay Variation), es la diferencia entre el CTD máximo y CTD mínimo. • Tasa de Celdas con Error (CER, Cell Error Ratio), define la facción de celdas entregadas con error. La Calidad de Servicio (QoS, Quality of Service) es el efecto colectivo del desempeño de un servicio, el cual determina el grado de satisfacción a la aplicación de un usuario. Para que en una red pueda ofrecer el manejo de QoS extremo-a-extremo (end2end), es necesario que todos los nodos o puntos de interconexión por los que viaje el paquete de información, posean mecanismos de QoS que ofrezcan un desempeño adecuado a la aplicación en cuestión . Los puntos de interconexión por los que pasa la información son los enrutadores, conmutadores, incluso los puntos de acceso al servicio (SAPs, Service Access Points) entre las capas del modelo de comunicación que se use. Cuando se establece una conexión con un nivel de QoS especificado, los parámetros de éste se traducen y negocian entre los diferentes subsistemas involucrados. Solamente cuando todos los subsistemas han llegado a acuerdos y pueden otorgar garantías respecto a los parámetros especificados, será que se satisfagan los requerimientos de QoS de extremo a extremo. Como se ve, para garantizar la QoS se requiere de la participación de un conjunto de elementos, estos elementos los podemos dividir en 3 grupos generales: 1. Aplicaciones .- Aquí la aplicación debe de manejar la señalización necesaria para hacer la negociación de parámetros con la red. 22 2. Acceso LAN .- Qué tipo de arquitectura de red, protocolos, mecanismos de calendarización y control de tráfico se usarán, así como control de admisión. 3. Acceso WAN .- Es la arquitectura de transporte de información que ofrece la capacidad de mantener el mínimo de retardo y pérdidas de información, por medio de mecanismos de diferenciación y control de tráfico. II.2.2.6.3 Objetivo: 1. Establecer y diferenciar las áreas de implementación de QoS en la dorsal de la red. 2. Especificar los parámetros de QoS que se medirán y como se medirán. 3. Implementar un escenario de pruebas de una aplicación multimedia. 4. Realizar la investigación de nuevos mecanismos de QoS que favorezcan un mejor desempeño de la red. II.2.2.6.4 Normas para regular la calidad de servicio en . Para responder a esto es necesario saber que tipos de servicios se especificarán dentro del compendio de servicio garantizado, porque es un hecho que no todo el tráfico que transite por la red deberá tener la misma prioridad de servicio. Sin embargo se requiere tener un amplio soporte de las iniciativas de QoS de Internet , para de esta manera poder establecer en forma natural las pruebas de aplicaciones a nivel internacional, lo cual daría un rol muy importante a la red.. Para poder brindar una garantía de servicio a las nuevas clases de aplicaciones de internet , se necesitará establecer los mecanismos de control de admisión, clasificación de servicios y control de tráfico. Actualmente está en estudio la implementación de una arquitectura de QoS para servicios diferenciados (DiffServ, Differentiated Services) estándar de la IETF, y otros como el de servicios integrados. 23 II.2.2.6.5 ¿Qué medir? Para los servicios que se les garantiza QoS en su transmisión son: • Sin pérdidas de paquetes. En particular no debe de haber pérdidas incluso en presencia de congestión. • Baja latencia. El retardo en los almacenadores temporales y procesamiento en los nodos de conmutación y enrutamiento debe de ser mínima, sin embargo se asume que habrá latencia en los enrutadores. • Bajo Jitter. La variación de retardo instantánea del paquete debe ser mínima, y con fronteras explícitas II.2.2.6.6 ¿Cómo medir la QoS? • Es necesario establecer un banco de prueba en el cual se pueda medir el desempeño a nivel de aplicación y de red y así establecer los puntos de medición. • Desarrollo e Implementación de herramientas que permitan medir parámetros de QoS en forma pasiva y activa. • La red QoS debe soportar una infraestructura de medición integrada que muestre un análisis de extremo-a-extremo donde estos resultados deben ser auditados por los usuarios, operadores de red e implementadores. Todos los datos de medición serán abiertos y compartidos por los participantes. La implantación de calidad de servicio (QoS) en el backbone es esencial para el éxito de aplicaciones avanzadas, como telemedicina, videoconferencia y VoIP (voz sobre IP o telefonía sobre IP). Estas aplicaciones demandan, además de gran ancho de banda, un servicio diferenciado. En muchos casos es necesario garantizar que la transmisión de los datos sea realizada sin interrupción o pérdida de paquetes. 24 II.2.2.6.7 ¿Por qué la necesidad de hacer un sistema de este tipo?. El termino sistema se utiliza de tantas maneras que a menuda es difícil llegar a una definición lo suficientemente extensa que abarque muchos usos y que a su vez sea concisa para que tenga un propósito útil. Una definición simple sería: un sistema es un conjunto de principios sobre una materia, enlazados entre si formando un cuerpo de doctrina o también podríamos definirla como: “conjunto ordenado de cosas que contribuyen a un fin”. Los objetos distintos que conforman los sistemas tienen propiedades de interés que interaccionan en el sistema, produciendo cambios en el mismo. A los sistemas, en que los cambios son predominantemente suaves se les conoce como sistemas continuos, mientras que a los sistemas en los cuales los cambios son predominantemente discontinuos, se les conoce como sistemas discretos. Hay pocos sistemas totalmente continuos o totalmente discretos. Sin embargo, en la mayoría de los sistemas predomina un tiempo de cambio, de manera que por lo general se puede clasificar a los sistemas como continuos o discretos. II.3 Eventos Discretos. Habiendo caracterizado a los sistemas discretos como aquellos en los cuales los cambios son predominantemente discontinuos, se utilizara el término evento para describir la ocurrencia de un cambio en un punto en el tiempo. Debido a que la técnica de simulación consiste en seguir los cambios de un modelo en un sistema, el simular sistemas discretos requiere construir un programa en el que sea posible seguir la secuencia de los eventos. 25 Los sistemas discretos tienen numerosas aplicaciones, las más populares son utilizadas en sistemas digitales, donde el reloj define el intervalo de tiempo. Pero, los sistemas discretos son frecuentemente usados como aproximaciones de sistemas continuos, definiendo la forma en que el estado actual del sistema cambie por la acción de una entrada externa. II.4 Simulación de Redes La simulación ayuda a predecir el comportamiento / rendimiento de una red antes de su implantación. Usando herramientas sofisticadas que simulan diferentes componentes, protocolos tal como Ethernet, Token Ring, Novell, TCP/IP, X.25, Frame Relay, ATM, algoritmos de enrutamiento, tráfico, etc; permiten visualizar problemas de utilización, alternativas de enrutamiento, grado de confiabilidad, y más. Se puede visualizar el tráfico en las troncales (trunks) para obtener la configuración óptima de los nodos. El propósito es entender el desempeño de la red y su confiabilidad antes de una implantación costosa. Además, se puede simular el impacto de nuevas aplicaciones y nuevos servicios en el rendimiento de la red. Una simulación tiene que ser parte de cada implantación o cada cambio significativo, para obtener el mejor diseño y rendimiento, además de bajar los costos, tiempo de instalación y operación de la red. II.5 ¿Qué es JAVA?. Los programas desarrollados en Java presentan diversas ventajas frente a los desarrollados en otros lenguajes como C/C++. La ejecución de programas en Java tiene muchas posibilidades: ejecución como aplicación independiente (Stand-alone Application), ejecución como applet, ejecución como servlet, etc. Un applet es una aplicación especial que se ejecuta dentro de un navegador o browser (por ejemplo Netscape Navigator o Internet Explorer) al cargar una página HTML desde un servidor Web. El applet se descarga desde el servidor y no requiere instalación en 26 el ordenador donde se encuentra el browser. Un servlet es una aplicación sin interfase gráfica que se ejecuta en un servidor de Internet. La ejecución como aplicación independiente es análoga a los programas desarrollados con otros lenguajes. Además de incorporar la ejecución como Applet, Java permite fácilmente el desarrollo tanto de arquitecturas cliente-servidor como de aplicaciones distribuidas, consistentes en crear aplicaciones capaces de conectarse a otros ordenadores y ejecutar tareas en varios ordenadores simultáneamente, repartiendo por lo tanto el trabajo. Aunque también otros lenguajes de programación permiten crear aplicaciones de este tipo, Java incorpora en su propio API estas funcionalidades. II.6 Programación utilizando Hilos de ejecución (Threads). Un programa Multihilo contiene 2 o más partes que se pueden ejecutar de manera concurrente o simultánea. Cada parte del programa se denomina hilo (thread), y cada hilo define un camino de ejecución independiente. Por lo tanto, la programación multihilo es una forma especializada de multitarea. En un entorno multitarea basado en hilos, el hilo es la unidad de código más pequeña que se puede seleccionar, esto significa que un solo programa puede realizar 2 o más tareas simultáneamente. La multitarea basada en hilos permite escribir programas muy eficientes que hacen una utilización óptima del CPU, ya que el tiempo que este se encuentra libre se reduce al mínimo. Esto tiene gran importancia en los entornos de red interactivos en los que funciona JAVA, donde hay mucho tiempo libre en la CPU. Por ejemplo, la velocidad de transmisión de datos en la red es mucho más baja que la velocidad de proceso del computador, entonces, en un entorno tradicional de un solo hilo, el programa tiene que esperar que se ejecuten y se procesen cada una de estas tareas, para poder procesar la siguiente, mientras que el entorno multihilo permite aprovechar estos tiempos de inactividad. 27 II.7 ¿Qué es SWING?. SWING es un conjunto de bibliotecas de clases que implementan los elementos o componentes gráficos para la creación de interfaces gráficas de usuario., proporciona componentes flexibles y potentes. Además de los componentes habituales, como botones, casillas de verificación y etiquetas, SWING proporciona varias funcionalidades interesantes como fichas, paneles con Scroll, tablas; incluso los componentes habituales como los botones, son más potentes en SWING (por ejemplo, un botón puede estar asociado a una imagen y a un texto). Su principal novedad es que casi todos sus componentes están, codificados completamente en JAVA, de modo que su comportamiento es el mismo en todas las plataformas. 28 Capítulo III: Diseño y especificaciones. En este capítulo se presentará la identificación de las entidades que componen la visualización, así como las interacciones que se dan entre ellas y su especificación en TDSO. III.1 Entidades que componen la visualización y su interacción con el usuario. Para el diseño de la visualización se crearon diferentes entidades; cada una de estas cumple una función específica. Se dividen en dos grupos, las entidades visibles y las entidades no visibles. Las entidades visibles son: 1. La visualización. 2. El enrutador. 3. La red. 4. Componente. 5. Las gráficas de control de flujo de datos. Estas entidades son las encargadas de la representación gráfica de los diferentes elementos, además también son las encargadas de llevar a cabo las tareas de esos elementos. Algunas de estas entidades tienen sus cuadros de diálogo para cambiar su configuración y editarlas. Las entidades no visibles son las encargadas de realizar parte del procesamiento interno, estas entidades son: 6. El paquete. 7. El algoritmo. Las entidades Enrutador y Red descienden de Componente, allí es donde se asignan las propiedades de los botones y donde se manejan los eventos, y otras opciones comunes a estas entidades. 29 III.1.1 La visualización. La visualización es el marco principal de ejecución del resto de las entidades, además es la ventana de la mayoría de las entidades gráficas. En ella se encuentran también los menús para agregar otras entidades, editar los parámetros generales, guardar las redes creadas, cargarlas y manejar su ejecución. Esta entidad también es la encargada de refrescar las gráficas de control de flujo de datos, utilizando para esto un temporizador (Timer) que actualiza el valor de los contadores y medias de paquetes perdidos y corruptos y los paquetes enviados por todas las entidades contenidas en la visualización. En general es el espacio de trabajo; se ha escogido un tamaño de 640 por 480 para esta ventana, ya que este es la resolución mínima presentada por las computadoras personales de hoy en día. Los menús presentados por esta entidad son: archivo, editar, y ejecución. La ventana tiene un contenedor donde se colocan las redes y los enrutadores. III.1.1.1 El menú archivo. El menú archivo presenta opciones para guardar y cargar los archivos de las redes creadas en esta herramienta, presenta también la opción de salir de la herramienta en cualquier momento. III.1.1.2 El menú edición. Presenta las opciones para agregar enrutadores y redes, así como la opción para editar los parámetros de visualización, tales como el tiempo de refresco de las gráficas. La escala de tiempo usada como referencia por las demás entidades, a excepción de las gráficas de control de flujo de datos y los paquetes, debe ser lo suficientemente grande como para que los temporizadores del resto de las entidades logren tener un buen tiempo de respuesta y evitar también la sobrecarga de la computadora donde se ejecute la visualización. Las opciones de las gráficas que se han de presentar, son la gráfica de paquetes enviados, perdidos, corruptos totales o la misma gráfica en un intervalo periódico de tiempo y el tiempo de refrescamiento de las gráficas. 30 III.1.1.3 El menú ejecución. Este menú contiene tres opciones, ejecutar, pausar y detener, estas acciones se llevan a cabo sobre todas las entidades que contiene la visualización. III.1.2 El enrutador. La función de este componente es dirigir los paquetes que pasan a través de él, utilizando el algoritmo escogido por el usuario, esta es una función tipo thread. Periódicamente mantiene actualizadas las tablas de enrutamiento del algoritmo y envía el paquete que este de primero en la cola de espera del algoritmo. Su función gráfica además de representar un enrutador, es colocar el menú para la edición de las propiedades de la entidad, las opciones presentadas en este menú son: Selecciona algoritmo: Lanza un cuadro de diálogo para asignar un algoritmo de enrutamiento. Enlazar: Enlaza este enrutador con una red, mostrando luego un cuadro de diálogo para asignar una dirección IP a este enrutador. Algoritmo: Es un menú contextual, que cambia según el algoritmo de enrutamiento que se esté utilizando. Dirección IP: Muestra un cuadro de diálogo para escoger una de las redes a la que esté conectado este enrutador y luego otro cuadro de diálogo para cambiar el valor de la dirección IP en la red seleccionada. Eliminar enlace: En un cuadro de diálogo muestra las diferentes direcciones IP que tiene este enrutador para que el usuario seleccione una y elimine así el enlace que tiene esa IP. Información: Esta opción pertenece a componente, pero el que toma la acción es Enrutador. Un diálogo de información es desplegado conteniendo lo siguiente: Información sobre todas las 31 interfaces(conexiones) que posee el Enrutador con sus direcciones IP, cantidad de paquetes perdidos y corruptos en esta interfaz y la cantidad en bytes de entrada y salida que han atravesado el enrutador III.1.3 La red. Su función es crear paquetes periódicamente y enviarlos a través de su ruta por defecto, y transportar los paquetes que pasen a través de ella a todos los Enrutadores que estén conectados a ella, estos se encargarán de revisar si el paquete es para ellos y procesarlos como sea debido. Los tiempos de retardo en el procesamiento de los paquetes y generación de paquetes son manejados con dos temporizadores, que son periódicos y tienen distintos tiempos de respuesta, estos temporizadores son manejados a través de threads, los temporizadores corren hasta que el thread que los maneja sea detenido. Su función gráfica es representar una red a la que se pueden conectar los enrutadores y presentar el menú de configuración de la red, en este menú se encuentran las siguientes opciones: Gateway: Muestra un cuadro de diálogo para seleccionar al gateway o ruta por defecto de esta red. Dirección IP: Se presenta un cuadro de diálogo para escribir la dirección IP de esta red. Máscara: Esta opción despliega un cuadro de diálogo donde el usuario debe escribir la mascara de esta red. Retardo generación: El usuario debe escribir en el cuadro de diálogo que aparece, un entero positivo que indica el tiempo que tarda la red en generar un paquete. Información: Describiremos aquí esta opción, ya que la información aquí mostrada depende de la entidad Red, pero esta opción es colocada en el menú por Componente. Muestra un cuadro de información que contiene la dirección IP de la red, su máscara, la cantidad de paquetes que han pasado por esta Red, la cantidad de bytes transportados, y el número de paquetes que se han perdido y corrompido en esta red. 32 III.1.4 El Componente. A pesar de no ser una entidad hablaremos aquí de él, debido a que contiene las características comunes entre la Red y el Enrutador, no es visible pero estas entidades toman de el sus propiedades comunes, como su tamaño, 38 pixeles de ancho y 38 pixeles de alto, los métodos que permiten que tanto la Red como el Enrutador se muevan a través del panel de la visualización que los contiene, el procesamiento de eventos generados por las entidades derivadas, encargándose aquellas, sólo de los eventos que esta entidad no sepa como manejar, el dibujo de la imagen representativa de estas entidades. En si, el componente es solo una clase abstracta que extiende la clase botón e implementa las distintas interfaces necesarias tanto para el manejo de eventos como para que estas entidades se comporten como threads. También funciona como un enlace entre ambas entidades ya que al ser subclases de él, ambas pueden ser contenidas dentro de un objeto del tipo Componente y la visualización los tratará como tal, pudiendo así referirse a cualquiera de ellos indistintamente. También contiene el menú de configuración común a ambas entidades, en este menú se presentan las siguientes opciones: Retardo: Despliega un cuadro de diálogo para asignar el tiempo de retardo en el procesamiento o envío de paquetes. Información: Muestra la información de la entidad, esto depende de la entidad a la que se le solicite información. Mover: Hace que la entidad siga al ratón por toda la interfaz contenedora. Pegar: Al seleccionar esta opción la entidad deja de seguir al ratón. Eliminar: Elimina a la entidad destruyendo cualquier referencia que se tenga dentro de la aplicación. 33 III.1.5 Las gráficas de control de flujo de datos. En la aplicación se pueden presentar dos tipos de gráficas, las gráficas de medición por intervalos de tiempo y las gráficas de medición acumulativa. Las primeras van dibujando los valores pico de cada una de las variables en un intervalo de tiempo especificado por el usuario y los vuelven a iniciar a cero cada ciclo(a excepción de la media que es acumulativa), y las otras simplemente van acumulando los valores para ir dibujando por ejemplo la cantidad total de paquetes perdidos en el tiempo por defecto. Todos los parámetros de estas gráficas son tomados directamente de la visualización, y los valores que ella leen son actualizados por las mismas entidades cada vez que ocurre un envío de paquetes, una pérdida o la corrupción de alguno de los paquetes. Para dibujar las gráficas se utilizaron las facilidades del API Java2D, creando áreas a las cuales se les van agregando nuevas áreas que contienen los últimos valores adquiridos en la ejecución. III.1.6 El paquete. La entidad paquete es la que simula la comunicación entre las distintas entidades que componen la visualización, también es utilizada por los enrutadores para la comunicación real en el pase de mensajes entre ellos (como el envío de tablas de enrutamiento muy necesario para los algoritmos dinámicos). La mayoría de los métodos de esta entidad son utilitarios y son utilizados por el resto de las entidades para el chequeo de errores. III.1.7 El Algoritmo. Esta entidad se puede considerar el corazón de la aplicación, ya que es la encargada de realizar la mayoría de los cálculos que se llevan a cabo dentro de la visualización, debe realizar el indexado de las tablas de enrutamiento, la búsqueda de las rutas que deben seguir los paquetes, la actualización de las tablas de enrutamiento en el caso de los algoritmos dinámicos, además de las 34 funciones agregadas por las clases que deriven de ella. Utilizan una cola de prioridades en el caso de que se utilice QoS, y enviar los paquetes que están en la cola de espera en el enrutador. Algunos de los algoritmos de enrutamiento implementados para las pruebas son: Estático, Inundación, Dinámico descentralizado (utilizando como métrica el tiempo de retardo), Dinámico centralizado (utilizando como métrica los saltos requeridos), y los algoritmos estático y dinámico descentralizado con QoS. Esta clase contiene un menú básico para el manejo de los algoritmos de enrutamiento, este se muestra como un submenú del menú de la entidad Enrutador; se hizo de esta manera para convertir así el menú de la entidad enrutador en un menú contextual, es decir las opciones presentadas en este menú cambian según el algoritmo que haya seleccionado el usuario para el enrutador, la única opción que está presente en cualquier menú de configuración del algoritmo es la de asignar ruta por defecto, esta opción asigna la ruta que han de seguir los paquetes, si todas las demás rutas fallan. Los nuevos algoritmos de enrutamiento deben implementar esta clase y debe pertenecer al paquete org.ula.sistemas.algoritmo; para agregar nuevos algoritmos de enrutamiento se debe editar el archivo algoritmos.ini que se encuentran en el directorio org/ula/sistemas/algoritmos/ , agregando al final el nombre de la clase donde se implementa el algoritmo. III.2 Interacciones entre los componentes. Aquí describiremos las diferentes interacciones que pueden darse entre las entidades, para resolver como han de comportarse los componentes ante las diferentes situaciones. III.2.1 Conexiones de las entidades. Antes de comenzar a describir las interacciones hay que ver como es el diagrama de conexión entre las entidades. Los elementos interactúan con el elemento que está directamente sobre ellos(padre o contenedor), a su mismo nivel (hermanos), o directamente debajo de ellos(hijo o contenido). 35 Figura 3-1. Conexión de las entidades La siguiente es la Representación gráfica del mismo árbol. Paquete Red Enrutador Visualización Gráficas Figura 3-2. Visualización de la conexión de las entidades. De la visualización. Las interacciones de la visualización se dan con las siguientes entidades Enrutador, Red y Gráficas, aquí explicaremos cuales son esas interacciones y la función de cada una de ellas, no se hablará de las interacciones como componentes de SWING. III.2.1.1 Con el Enrutador y la Red. III.2.1.1.1 Creación de enrutadores y redes. Una vez que el usuario indica que entidad debe crearse y agregarse a la visualización , la visualización se encarga de crear instancias de estas entidades. 36 III.2.1.1.2 Obtención de información. Esta interacción se llevan a cabo en ambos sentidos. Los enrutadores deben saber a que redes se pueden conectar, así cuando un enrutador necesita saber cuantas redes disponibles para la conexión hay en la visualización le solicitan esa información a la visualización, los algoritmos disponibles para la carga es otra información solicitada por los enrutadores. Las redes también deben solicitar información sobre otras redes para enviar paquetes, cuando se les asigna una IP y desean saber si alguien ya esta utilizando esa dirección. La visualización debe estar al tanto de cuantos paquetes perdidos, corruptos y enviados hay en todo momento, los enrutadores y redes realizan la tarea de actualizar la información contenida en la visualización sobre estos datos. III.2.1.1.3 Inicio, pausa y parada de la ejecución. El menú ejecución genera un evento que es capturado por la visualización, luego la visualización lo propaga a través de cada uno de las entidades que están contenidas dentro de ella. III.2.1.2 Con las Gráficas. III.2.1.2.1 Despliegue de gráficas. Cuando se lanza el evento para ejecutar la visualización, se hacen visibles las gráficas que el usuario haya seleccionado para ser dibujadas. III.2.1.2.2 Actualización de gráficos. Una vez obtenida la información, la visualización es la encargada de mantener actualizadas las gráficas de control de flujo de datos. Para llevar a cabo esta tarea utiliza un temporizador periódico cuyo retardo debe ser asignado por el usuario, cuando el temporizador finaliza la visualización captura el evento y agrega a las gráficas una nueva línea conteniendo los últimos datos que se han adquirido. III.2.2 De los Enrutadores. 37 Los enrutadores, son uno de los elementos más importantes debido a que es el que más se comunica. Las entidades con las que interactúa son las siguientes: Visualización, Redes, Algoritmos, Paquetes, y otros Enrutadores. III.2.2.1 Con la Visualización. Estas interacciones fueron explicadas en la sección anterior. III.2.2.2 Con la Red. III.2.2.2.1 Solicitud de información. Una vez que el usuario decide conectar el enrutador a una red este solicita la dirección IP de la red para no conectarse con ella dos veces y para no utilizar una dirección que ya este siendo utilizada por otro enrutador, también necesita obtener información sobre los otros enrutadores que están conectados a la red. III.2.2.2.2 Envío de paquetes. Cuando se termina el temporizador de retardo para el envío de paquetes, la red se comunica con todos los enrutadores que estén conectados a ella para entregarles el paquete, el enrutador obtiene la dirección IP y la mascara de la red, le aplica a su dirección IP la máscara para saber si se trata de un paquete para el o si se trata de un paquete que debe ser enviado a otra(s) red(es). Cuando es el enrutador el que va a enviar un paquete, debe preguntarle a la red por la que se envía si está ocupada en ese momento para enviar el paquete. III.2.2.3 Con los paquetes. III.2.2.3.1 Envío. Para el envío el enrutador debe revisar varios de los atributos del paquete, entre estos se encuentran, el Tiempo de vida del paquete que debe ser actualizado para el siguiente reenvío del 38 paquete, la dirección IP de destino para que el algoritmo sepa por que ruta ha de ser enviado el paquete, si el paquete es para el enrutador, entonces al algoritmo debe revisar la información contenida en él para que el algoritmo la procese debidamente. III.2.2.3.2 Corrección de errores. El Enrutador utiliza muchos de los métodos del paquete para la corrección de errores en la entrada de datos. Los métodos utilizados son ipCheck, ipValue, readableValue y send. III.2.2.4 Con los Algoritmos. Los enrutadores y los algoritmos son las entidades que más interactúan ya que el enrutador debe actualizar periódicamente las tablas de enrutamiento del algoritmo, además el enrutador debe cumplir el objetivo para el que fue diseñado que es el de dirigir el tráfico y esta función sin el algoritmo de enrutamiento no puede ser llevada a cabo. Básicamente el enrutador tiene dos temporizadores, uno para el procesamiento de paquetes, y otro para actualizar las tablas de enrutamiento, cada vez que uno de estos temporizadores produce un evento el enrutador debe recurrir a su algoritmo para que este realice esas tareas. III.3.1 Especificación en TDSO. En esta sección se expondrá el TDSO de las clases y métodos más importantes. Dando una breve explicación de cada uno de ellos, exponiendo las razones que existieron para utilizar cada una de las clases e interfaces. III.3.1.1 Arboles de herencia. Antes de comenzar a describir cada una de las clases daremos una breve vista de los árboles de herencia, estos árboles contendrán también las clases e interfaces de java de las que derivan directamente las entidades. ActionListener Object Algoritmo Estático Ruta Paquete Inundación Figura 3-3. Arbol de herencia de las clases Algoritmo, Ruta, Paquete, Estático e Inundación 39 Runnable ChangeListener JButton ActionListener MouseMotionListener Componente Enrutador Red Figura 3-4. Arbol de herencia de las clases Componente, Enrutador, Red. ActionListener JFrame MouseMotionListener Visualización Figura 3-5. Arbol de herencia de la clase Visualización Los nodos que aparecen en líneas punteadas son interfaces, las que aparecen con _.. son clases abstractas, se han omitido adrede las clases de poca importancia como la clase Gráfica y la clase Lienzo. III.3.1.1 Clase componente. Es una clase abstracta utilizada para el manejo de gráficos, para contener los atributos esenciales para los enrutadores y redes, y como una clase intermedia para que la visualización maneje a ambas entidades como si de una sola se tratase. Implementa además interfaces necesarias para el funcionamiento gráfico y a nivel de aplicación de las entidades que de ella derivan. Componente extiende JButton implementa ActionListener, MouseMotionListener, Runnable, 40 ChangeListener Atributos privados: bytes_corruptos bytes_entrada bytes_perdidos bytes_salida cantidad_bytes cantidad_paquetes comandos corruptos_paq icono max_paq menú móvil paquetes_entrada paquetes_corruptos paquetes_perdidos paquetes_salida pause perdidos_paq retardo running visu timer tipo Descripción bytes_corruptos : Entero, especifica la cantidad de bytes que se han corrompido en este componente. bytes_entrada: Entero, representa la cantidad de bytes que han entrado a este componente. bytes_salida: Entero, cantidad de bytes que han salido de este componente. cantidad_bytes: Entero, cantidad total de bytes que han pasado por este componente. cantidad_paquetes: Entero, cantidad de paquetes que han pasado por este componente. comandos: Lista enlazada (LinkedList), contiene todos los comandos que han de ser agregados al menú del componente. corruptos_paq: Entero, este atributo junto con max_paq, establecen la probabilidad de perder un paquete, esto quiere decir que de max_paq paquetes enviados corruptos_paq han de estar corruptos. Icono: Icono(ImageIcon), contiene el dibujo de representación de este componente. max_paq: Entero, este campo junto con corruptos_paq y perdidos_paq establece la probabilidad de corromper y perder paquetes. menú: Menú(JpopupMenu), contiene el menú que se despliega cuando se pulsa un botón del ratón sobre el componente. móvil: Booleano, indica si el componente debe seguir o no al ratón. paquetes_entrada: Entero, indica la cantidad de paquetes que han entrado a este componente. paquetes_corruptos: Entero, cantidad de paquetes han sido corruptos por este componente. paquetes_perdidos: Entero, cantidad de paquetes que se han perdido al pasar por este componente. paquetes_salida: cantidad de paquetes que han salido de 41 este componente. pause: Booleano, indica si el componente en este momento está en pausa. perdidos_paq: Entero, junto con max_paq indica la probabilidad de perder un paquete, es decir perdidos_paq paquetes de max_paq paquetes enviados serán perdidos en este componente. retardo: Entero, es la cantidad de tiempo que tarda en ser procesado un paquete en este componente. running: Booleano, indica si este componente se está ejecutando o no. visu: Visualización, contenedor de este componente, se utiliza para obtener información. timer: Temporizador(javax.swing.Timer), utilizado para generar eventos de envío y procesado de paquetes cada (retardo*visu.escala_tiempo) milisegundos. tipo: Entero, indica de que tipo de objeto se trata, si es un Enrutador su valor será 0, si es una Red 1. 42 Constructores Componente(ImageIcon ico) Métodos actionPerformed(ActionEvent ev): ∅ createMenu():∅ abstracto eliminar():∅ getDelay():Entero abstracto getInfo():String getTipo():Entero inicio():∅ abstracto isReady():Booleano mouseDragged(MouseEvent ev) : ∅ mouseMoved(MouseEvent ev) : ∅ parada():∅ pause() : ∅ setContenedor(Visualizacion s): ∅ setDelay(int tiempo): ∅ stateChanged(ChangeEvent e): ∅ abstract takeAction(String c) : Booleano abstract timerAction(Timer t): ∅ estático tohtml(String cad):String Descripción Construye un nuevo componente, asignándole ico como su icono Descripción actionPerformed Es un método heredado de la interfaz ActionListener, aquí se toman las decisiones con respecto a los eventos generados por el objeto. createMenu: Se encarga de crear el menú, una vez que la clase derivada le agrega sus propias acciones. eliminar: Este método debe ser implementado por las clases derivadas para eliminar el objeto de la visualización. getDelay: devuelve un entero que representa el tiempo de retardo de esta clase. getInfo: este método devuelve una cadena conteniendo la información de la clase en formato HTML. getTipo: devuelve un entero que representa el tipo de la clase que extiende a esta. inicio: este método crea un thread para ejecutar el componente e inicia el temporizador de procesamiento de paquetes. isReady: devuelve verdadero si el componente está listo para ejecutarse(si todas la configuraciones ya fueron hechas), y falso si el componente no está bien configurado. mouseDragged: Método para mover el componente a través de la visualización arrastrándolo. mouseMoved: Método para mover el componente a través de la visualización si este es móvil, sino mueve el que sea móvil en ese momento. parada: Detiene la ejecución del thread y el temporizador. Luego cuando se reinicie la ejecución también lo harán las estadísticas. pause: Detiene momentáneamente la ejecución del thread y el temporizador, cuando se inicie de nuevo la ejecución las estadísticas continuarán. setContenedor: Le asigna a este objeto una visualización, de la cual obtendrá todos sus datos. setDelay: Asigna un tiempo de retardo al temporizador del componente. stateChanged: Verifica cuando este componente se hace 43 visible, y le agrega el menú. takeAction: si el método actionPerformed no atrapa el evento generado por este componente entonces este método debe estar escrito para tomarlo, devuelve un booleano que indica si el evento fue capturado en el cuerpo de este método. timerAction: toma los eventos del temporizador(es) y los procesa, es un método abstracto. tohtml: Toma la cadena de parámetro, y la transforma en una cadena HTML. Tabla 3-1. Especificación en TDSO de la clase componente. 44 III.3.1.2 Clase Algoritmo. Esta clase es una de las más importantes, ya que gracias a ella se logra desarrollar casi cualquier tipo de algoritmo de enrutamiento, está pensada de manera que el enrutador no necesite saber el nombre de la clase que implementa el algoritmo para lograr utilizarla. Esto supone una ventaja ya que no se necesita modificar el código de la clase enrutador para utilizar un algoritmo de enrutamiento desarrollado por otro(s). Clase Algoritmo extiende Object Atributos Privados: menú. comandos. dueno. por_defecto. rutas. Descripción menu: JMenu, es el menú contextual del algoritmo. comandos: Lista enlazada(LinkedList), que contiene los comandos que han de ser agregados al menú contextual del enrutador. dueno: Enrutador, es el enrutador en el cual se está ejecutando el algoritmo de enrutamiento. por_defecto: Ruta, es la ruta que han de seguir los paquetes si no hay otras en la tabla de enrutamiento. rutas: Tabla hash (Hashtable), contiene la tabla de enrutamiento del algoritmo. Constructores Algoritmo() Métodos actionPerformed(ActionEvent ev) :∅ createMenu():∅ abstracto encola(Paquete p, Red r):∅ abstracto getInfo():String abstracto isReady():Booleano procesa(Paquete p, Red r):∅ abstracto send():∅ setDueno(Enrutador e):∅ abstracto takeAction(String comando):Booleano estático tohtml(String cad):String abstracto update():∅ Construye e inicializa las variables básicas de todo algoritmo de enrutamiento, las clases que deriven de esta deben llamar al constructor antes de ejecutar cualquier otra acción. actionPerformed: método que se encarga de procesar cualquier evento, si no contiene el código para manejar el evento lo pasa a takeAction. createMenu: este método es el encargado de crear al menú contextual de todos los algoritmos, debe ser invocado justo antes de finalizar el constructor de la clase derivada. encola: Este método abstracto agrega a la cola de paquetes, que puede ser una cola de prioridades, el paquete que se desea enviar junto con la red de donde procede. getInfo: regresa la información de este enrutador, 45 se puede escribir información sobre el autor para que sea desplegada. isReady: regresa un Booleano que indica si este enrutador esta listo para ejecutarse, este método debe estar implementado en la clase que extienda a esta. procesa: Este método es llamado por el enrutador una vez que determina que el paquete enviado es para el, su función es procesar comandos de comunicación entre enrutadores. send: Lo invoca el enrutador cuando expira el temporizador de retardo para el envío de paquetes. setDueno: asigna el enrutador donde se ejecuta el algoritmo de enrutamiento. takeAction: se encarga de los eventos que actionPerformed no sepa como manejar. tohtml: Convierte la cadena que se le pasa como parámetro a una cadena con una cabecera en HTML, para la generación de menús y la generación de información. update: este método es invocado por el enrutador, cada vez que expira el tiempo de actualización, es el encargado de actualizar las tablas de enrutamiento. Tabla 3-2. Especificación en TDSO de la clase Algoritmo. III.3.1.3 La clase Enrutador. La clase enrutador es la encargada de ejecutar el algoritmo de enrutamiento, actualizar sus tablas, además de servir como intermediario en la comunicación entre redes y otros enrutadores con los algoritmos de enrutamiento. Se encarga de la representación gráfica, y de mostrar los menús de configuración tanto los propios como los menús contextuales de los algoritmos de enrutamiento. Clase Enrutador extiende a Componente Descripción Atributos actualiza: Temporizador periódico, cada vez que Atributo públicos: expira se actualiza n las tablas del algoritmo de algoritmo. enrutamiento, si este es dinámico. LinkedList dirip. LinkedList redes. 46 algoritmo: Algoritmo, este atributo almacena el algoritmo de enrutamiento usado por este enrutador. Atributos privados: actualiza. tipo. dirip: Lista enlazada que almacena las direcciones ip de este enrutador en las distintas redes a las que está conectado. redes: Lista enlazada que almacena las redes a las que este enrutador está conectado tipo: entero estático cuyo valor es igual al de Visualización.ENRUTADOR. Constructores Enrutador(Visualización s) Crea un enrutador asignándole como Visualización a v. Métodos getInfo() :String removeIp(Integer ip, Red r):∅ void run() getInfo: Método abstracto para obtener información del enrutador, que será desplegada en un cuadro de diálogo, contiene información sobre las conexiones del enrutador. removeIp: elimina la conexión del enrutador con una Red. void send(Paquete p, Red r) run: Implementa al método run heredado de la clase componente, este método inicia el temporizador de actualización y espera hasta que se termine de ejecutar la visualización. send: método invocado por la red para solicitar la recepción de un paquete. Tabla 3-3. Especificación en TDSO de la clase Enrutador. Se han dejado algunos métodos sin especificar, estos métodos son heredados de la clase abstracta Componente, por lo tanto su especificación ya se dio en la sección III.3.1.1, ahora pasaremos a especificar en TDSO los fragmentos de código más importantes. III.3.1.3.1 Carga de los algoritmos de enrutamiento. El siguiente fragmento de código está en el método takeAction, es el encargado de cargar una clase dado su nombre y crear una nueva instancia de dicha clase. 47 Leer(respuesta ); Si(respuesta ≠ ∅) entonces Class algorithm; si(algoritmo ≠ ∅) entonces menu.eliminar( algoritmo.menu ); fin si algorithm = Class.forName("org.ula.sistemas.algoritmos."+respuesta); algoritmo = algorithm.nuevaInstancia(); algoritmo.setDueno(this); fin si regresar verdadero; Tabla 3-4. Implantación en TDSO de algoritmo para cargar un algoritmo de enrutamiento. III.3.1.3.2 Especificación en TDSO del algoritmo de envío de paquetes. Otro de los algoritmos importantes en la clase Enrutador es el envío de paquetes, este algoritmo verifica si el paquete está dirigido al enrutador si es así le pasa el paquete al algoritmo para que lo procese. Esto se logra aplicando la dirección que tiene el paquete en su dirección de destino, por ejemplo un enrutador con la dirección IP 192.168.0.1, recibe un paquete que va dirigido a los host de la red 192.168.0.0, el paquete debe contener entonces en su dirección IP de destino lo siguiente 192.168.0.255, el enrutador aplica la máscara de la siguiente manera: Enrutador Dirección IP Dirección IP codificada en binario 192.168.0.1 11000000 10101000 0000000 000000001 Paquete 192.168.0.255 11000000 10101000 00000000 11111111 Resultado 192.168.0.1 11000000 10101000 00000000 00000001 Tabla 3-5. Aplicando una operación AND lógico sobre la dirección del paquete. 48 Si el paquete no es para el enrutador y este es la ruta por defecto de la red que lo envía, entonces pasa el evento al algoritmo para que este lo envíe. send(Paquete p,Red r):∅ {pre: p≠∅ ^ r≠∅} miip = dirip.ver(redes.indiceDe(r)); si( (p.dip & miip)=miip) entonces //reducimos el tiempo de vida del paquete p.send(); //Pasamos el paquete al algoritmo para que lo procese. Algoritmo.procesa(p); sino si(r.getGateway() = miip) entonces p.send(); //decimos al algoritmo que encole este paquete algoritmo.encola(p,r); fin si fin si regresa {pos: El paquete es recibido y procesado según sea necesario} miip: Entero, que representa la dirección IP del enrutador en la red que está enviado el paquete. p: Paquete que se recibe desde la red. r: Red, desde donde se está enviado el paquete. Tabla 3-6 Implantación en TDSO del algoritmo de envío de paquetes del enrutador III.3.1.4 Especificación en TDSO de la clase Paquete. La clase paquete es la que permite la comunicación entre los distintos componentes, esta clase tiene dos formas de ser utilizada. La primera es para la ser utilizada en la generación de estadísticas, enviando paquetes sin datos. Y la segunda es para el envío de información entre los enrutadores, para esto un enrutador construye un paquete con la información que desea comunicar, y lo envía hacia otros enrutadores. Atributos Privados: corrupto. Clase Paquete extiende a Object Descripción corrupto: Booleano, indica si el paquete esta corrupto o no . data. dip. data: Cadena, Si este paquete en contiene alguna data irá aquí. id. dip: Entero, Dirección IP de destino. 49 id: Entero, identificador de paquete, utilizado cuando se hace la fragmentación del paquete. mf. offset. mf: Booleano, Este campo indica si el paquete está fragmentado, su significado es “mas fragmentos” (more fragments). sip. size. offset: Entero, Si el paquete está fragmentado, este atributo representa el desplazamiento. ttl. sip: Dirección IP donde fue creado el paquete. size: Entero, tamaño del paquete. ttl: Byte, tiempo de vida del paquete. Constructores Paquete(byte t, int idp, int s, int d, int si) Paquete(byte t, int idp, String s, String d, String dat) Estático fragmentar(int mtu, Paquete p): Paquete[] Constructor usado por las redes, para crear paquetes con tamaño virtual. Constructor para humanos, también usado para pasar mensajes entre enrutadores fragmentar: Utilidad para fragmentar paquetes dado un MTU, devuelve un arreglo de paquetes donde están todos los fragmentos generados. Estático ipCheck(String s): Booleano Estático ipValue(String dirip): Entero Estático maskCheck(String s): Estático readableValue(int dirip): Cadena send():∅ ipCheck: Método de utilidad que comprueba si una dirección IP esta bien escrita, devuelve verdadero si está bien escrita y falso en caso contrario. ipValue: Método de utilidad para transformar direcciones IP legibles por humanos a direcciones IP entendibles por la visualización, devuelve un entero que representa la dirección IP. maskCheck: Método de utilidad que comprueba si una máscara esta bien escrita, devuelve verdadero si lo está y en caso contrario devuelve falso. readableValue: Método de utilidad para transformar valores en direcciones IP legibles por humanos. send: Reduce el tiempo de vida cada vez que sea reenviado este paquete. Tabla 3-7 Especificación en TDSO de la clase Paquete. 50 III.3.1.5 Especificación en TDSO de la clase Red. La red es la encargada de generar paquetes, sin ella la prueba del funcionamiento de los algoritmos de enrutamiento no se daría. Otra de sus tareas es permitir la comunicación entre los enrutadores. Clase Red extiende a Componente enrutadores: Lista enlazada, contiene los enrutadores que están conectados a la Red. enrutadores. gateway. gateway: Entero, contiene el índice del Enrutador por defecto. genera. genera: Temporizador periódico, es el que lanza el evento para general paquetes. genera_paquetes. ip. genera_paquetes: Entero, tiempo en milisegundos máscara. Visualización.escala_tiempo para generar paquetes. mtu. paquete. ip: Entero, contiene la dirección IP de esta red. máscara: Entero, máscara de la Red. mtu: Entero, tamaño máximo del paquete que debe tener para atravesar la red. paquete: contiene el paquete que ha de ser enviado cuando finalice el temporizador de retardo de envío. Constructores Red(Visualizacion v) Construye una red asignándole como su contenedor a la visualización v Métodos getGateway():Enrutador getGateway: devuelve el Enrutador utilizado como ruta por defecto en esta red. getTipo():Entero void paint(Graphics g) run():∅ send(Paquete p): ∅ getTipo: Devuelve Visualización.RED lo que indica que esta es una red. paint: método reimplementado de la clase Component, su función es la de dibujar los enlaces de esta red con los enrutadores 51 conectados a ella. run: Ejecuta esta red, iniciando el temporizador para crear paquetes y el temporizador de retardo de envío de paquetes, y el thread que espera a que termine la ejecución de la visualización. send: Cuando el temporizador de retardo de envío finaliza, llama a este método para que se envíe el paquete que está en espera. Tabla 3-8 Especificación en TDSO de la clase Red. III.3.1.6 Especificación en TDSO de la clase Visualización Clase Visualización extiende a JFrame implementa a ActionListener MouseMotionListener Atributos actual: Componente, es el componente que debe actual. seguir al ratón a través de todo el cuerpo de la visualización. algoritmos. componentes. algoritmos: Lista enlazada que contiene los nombres de los algoritmos de enrutamiento. Estático ENRUTADOR. escala_tiempo. fileChooser. iconoRed. iconoRouter. componentes: Lista enlazada de componentes que han sido agregados a la visualización. ENRUTADOR: Entero estático, que contiene el número que indica que el Componente es un enrutador. escala_tiempo: Entero, indica la escala de tiempo a utilizar al ejecutar los componentes. menuBar. nombreArchivo. ocupa . fileChooser: JFileChooser, utilizado al abrir y guardar archivos. iconoRed: Icono(ImageIcon), dibujo que representa a la red. pane. random. iconoRouter: Icono(ImageIcon), dibujo que representa al enrutador. Estático RED redes. saved menuBar: Barra de menú donde se agregan los menús. nombreArchivo: Cadena, nombre del archivo a salvar o abrir. 52 tothis. ocupa: Booleano, le indica a las acciones del los menús que en este momento la visualización está ocupada. pane: Panel por capas(JLayeredPane), aquí se agregan las representaciones gráficas de los componentes. random: Generador de números aleatorios(Random), utilizado por los componentes para general un valor al azar, para saber si los paquetes se pierden o se corrompen. RED: Entero, es el valor devuelto por la red cuando se ejecuta el método Red.getTipo() redes: Lista enlazada, que contiene las redes que se han agregado a la visualización, se utiliza para ahorrar tiempo de búsqueda. saved: Booleano, indica si la visualización que esta siendo vista en estos momentos ha sido modificado. tothis: Enrutador, contiene el enrutador que lanzó el evento de enlace, es utilizado por la Red para saber a que enrutador va a agregar a su lista de enrutadores. Constructores Visualización(). Construye una visualización inicializando todos sus atributos. Métodos add(Componente c):∅ Estático campo(String nombre):String add: Agrega un componente a la parte visible de la visualización y a la lista de componentes, si este componente es una red lo agrega también a la lista de redes. Protegido createMenus():∅ getRandomIp(int nothis):Entero campo: Utilidad para agregar colores a los nombres de los campos cuando se solicita la información de un objeto. isSaved():Booleano remove(Componente c) save():∅ saveAs():∅ createMenus: Método utilizado para crear los menús. getRandomIp: Busca en la lista de redes una dirección IP para, si la dirección IP es nothis, vuelve a intentar la búsqueda, este método es utilizado por las redes para enviar paquetes a 53 direcciones aleatorias. isSaved: Verifica si la visualización ha sido guardada, devuelve verdadero si esta red ya ha sido salvada, y falso en caso contrario. remove: Elimina un componente de la parte visible de la visualización, de la lista de componentes y si es una red lo elimina de la lista de redes. save: Este método es utilizado para almacenar en disco la visualización actual. saveAs: Salva la visualización con otro nombre. Tabla 3-9. Especificación en TDSO de la clase visualización. 54 Capítulo IV Implementación y pruebas. En el presente capítulo, se mostrarán los objetos que pertenecen al sistema con el fin de reconocer la estructura que se utilizó al programar en el lenguaje de programación Java. Luego se mostrarán algunos fragmentos del código fuente de las clases para entender como se lleva a cabo la comunicación entre las entidades. Por último se mostrarán algunas pruebas que muestran cuales son los tiempos de respuesta de una red, utilizando diferentes algoritmos de enrutamiento. IV.1 Clase Componente. La clase componente por ser una clase abstracta, no es agregada directamente a la visualización, sino que se utiliza en las clases Red y Enrutador como una forma de implementar la mayoría de los métodos que estos requieren para su funcionamiento. Esta clase hereda e implementa una gran cantidad de clases e interfaces, todo esto con el fin de simplificar el manejo de eventos y capacidades gráficas. Cualquier subclase de componente al ser creada debe invocar al constructor de la clase Componente, este se encarga de iniciar los valores de las variables comunes, crea los temporizadores, le asigna una imagen de representación, asigna los comandos básicos del menú y hace que Java le envíe todos los eventos que tengan que ver con la subclase. IV.1.1 El manejo de eventos. Como dijimos anteriormente el manejo de eventos es llevado a cabo por esta clase, cualquier evento que se produzca y que no sea manejado por esta clase, será procesado por las clases derivadas. 55 Figura 4-1. Visualización del menú del componente. Ventana principal de la visualización con dos componentes, el evento para desplegar el menú es interceptado por el método actionPerformed de la clase componente. A continuación se presenta un fragmento del código que procesa los eventos producidos por el menú del componente y por los clics del ratón sobre el: public void actionPerformed(ActionEvent ev){ String comando=ev.getActionCommand(),respuesta; int i,n; boolean ban; if(comando==null||comando.length()==0){ //revisa si es un evento d e los temporizadores timerAction((Timer)ev.getSource()); return; } if(comando.equals("Menu")){ //si la acción es mostrar el menú Point p1=getLocationOnScreen(); p1.x+=18; p1.y+=18; menu.setLocation(p1); menu.setVisible(true); return; } if(!takeAction(comando)){ if(comando.equals("Informaci&oacute;n")){ JoptionPane.showMessageDialog(visu,tohtml(getInfo())); 56 return; } if(comando.equals("Mover")){ ((JlayeredPane)getParent()).moveToFront(this); setActionCommand("Pegar"); visu.actual=this; movil=true; return; } ........ //aquí hay más eventos } Tabla 4-1. Fragmento de código encargado del proceso de eventos de los componentes. Analizando un poco el código anterior, el método actionPerformed es heredado de la interfaz ActionListener, esta interfaz es la encargada de procesar los clics del ratón, cuando el usuario presiona Enter mientras escribe en un cuadro de texto, cuando selecciona una opción en un menú, o cuando caduca un temporizador. Cuando se produce un evento, Java lo pasa a este método, primero comprueba si se trata de un evento producido por los temporizadores, en este caso llama al método abstracto timerAction para que procese el evento. Si no es un evento de temporizador, revisa si se trata del evento mostrar Menú para desplegar el menú del componente. Luego llama al método abstracto takeAction, este método debe estar implementado en la subclase, y debe revisar si el comando de este evento es alguno de los comandos agregados por la subclase este método lo procesa y devuelve verdadero, en caso contrario regresa falso y se analiza el resto de los comandos que están dentro de este método. En el siguiente código se presenta un ejemplo de como deben implementar las subclases los métodos takeAction y timerAction: public boolean takeAction(String comando){ int i,n,dip=0,k,l; String dir,mask,respuesta; Red red; Enrutador enru; Boolean ban; if(comando.equals("Enlazar")){ //si el comando es enlazar ........ //codigo que implementa el enlace de la red return true; } .........//resto de los comandos agregados por la entidad } Tabla 4-2. Ejemplo de método takeAction tomado de la clase Red. 57 public void timerAction(Timer t){ if(t==timer2){ //si es el timer de actualización //si es un algoritmo estetico no necesita actualización automática if(algoritmo.getTipo()==Algoritmo.ESTATICO) timer2.stop(); else algoritmo.update(); }else{ //sino envío algoritmo.send(); } } Tabla 4-3. Ejemplo de método timerAction tomado de la clase Enrutador. El siguiente fragmento de código se encarga de procesar los movimientos del ratón, cada vez que el ratón pase sobre el componente, será llamado este evento para que actualice la posición del objeto que es móvil en ese momento: public void mouseMoved(MouseEvent ev){ Point p=getLocation(); GetParent().repaint(); if(movil){ //si es este objeto int i; p.x+=ev.getX()-19; p.y+=ev.getY()-19; setLocation(p); }else{ if(visu.actual!=null){ //si es un objeto externo p.x+=ev.getX()-19; p.y+=ev.getY()-19; visu.actual.setLocation(p); } } Tabla 4-4. Fragmento de código para procesar el movimiento de ratón. Este método es muy parecido al mouseDragged pero la diferencia radica en que el evento mouseDragged siempre se usa para mover este mismo componente, mientras que este método debe revisar si se trata de un objeto externo lo que queremos mover. El último de los eventos manejados es cambio de estado (stateChaged), se procesa este evento para agregar el menú del objeto una sola vez al panel contenedor. 58 IV.1.2 El funcionamiento de los hilos Como se dijo en capítulos anteriores esta clase también se encarga del manejo de Las redes y los enrutadores como hilos, así que para que una entidad sea ejecutada debe llamarse al método inicio, este crea un hilo con el objeto dentro y se encarga de ejecutar a la entidad. A continuación se presenta el código de estos métodos: public void inicio() { //inicia la ejecución del thread if(!isReady()) return; //si no esta listo no corre Thread thread=new Thread(this); //creamos un nuevo hilo thread.start(); //lo iniciamos }; public void run(){ //ejecuta a la entidad do{ while(visu.pause); //espera a que finalice la pausa de sincronización //inicia los temporizadores timer1.start(); timer2.start(); //mientras la visualización este corriendo y no este en pausa while(!visu.pause&&visu.running); //detenemos los temporizadores timer1.stop(); timer2.stop(); }while(visu.pause); //mientras la visualización este en pausa parada(); //paramos la ejecución } Tabla 4-5. Código de los métodos que ejecutan a la entidad tomado de la clase componente. Cuando la visualización se inicia debe ejecutar el siguiente código: if(subacu.isEnabled()) graficas[1].setVisible(true); //si están activadas las gráficas acumulativas if(subtem.isEnabled()) graficas[0].setVisible(true); //si están activadas las gráficas periódicas if(running&&!pause) return; //si ya está corriendo no hacemos nada if(pause){ //si se produce despues de una pausa pause=false; return; } n=componentes.size(); pause=true;//ponemos la pausa de sincronización running=true; actualiza.start(); 59 for(i=0;i<n;i++){ imagen=((Componente)componentes.get(i)); //si alguna entidad no está lista paramos la visualización por completo if(!imagen.isReady()){ running=false; pause=false; graficas[1].setVisible(false); graficas[0].setVisible(false); actualiza.stop(); addEvent("La ejecucion ha sido detenida..."); addEvent((imagen.geTipo()==ENRUTADOR?"El enrutador ":"La red ")+"no est&aacute list"+(imagen.geTipo()==ENRUTADOR?"o":"a")+"..."); break; } imagen.inicio(); } pause=false; //quitamos la pausa de sincronizacion Tabla 4-6. Código para iniciar la ejecución de las entidades. Como las clases red y enrutador derivan de la clase componente la mayoría de las acciones realizadas por esto, están dentro de componente, por lo tanto no se analizarán las estas clases en este capítulo. IV.2 Clase Algoritmo La clase algoritmo es muy parecida en cuanto a concepto a la clase Componente, es decir es utilizada para procesar los eventos más comunes que tengan que ver con los algoritmos (los eventos que se producen en el menú de configuración), y para que los enrutadores utilicen cualquier tipo de algoritmo de enrutamiento, además contiene un método básico para el manejo de la comunicación entre enrutadores, a continuación presentamos algunos fragmentos del código que realizan estas funciones. IV 2.1 Los Eventos La clase algoritmo maneja los eventos del menú de forma parecida a la clase Componente, no maneja eventos de movimiento de ratón debido a que el algoritmo no es una entidad gráfica. Cuando llega un evento del menú al algoritmo este revisa si el comando se encuentra en la lista de comandos de la subclase, si no se encuentra revisa las otras opciones posibles que hay entre los comandos básicos de configuración y regresa. 60 Los siguientes fragmentos de código fueron extraídos de la clase Estático que es un algoritmo de enrutamiento: public boolean takeAction(String comando){ int i,n; Componente c; If(comando=="Agregar Ruta"){ n=dueno.visu.componentes.size(); for(i=0;i<n;i++){ c=((Componente)dueno.visu.componentes.get(i)); if(c.getTipo()==Visualizacion.ENRUTADOR){ c.setEnabled(false); }else{ if(c.getTipo()==Visualizacion.RED){ c.removeActionListener(c); c.setActionCommand("Red"+Paquete.readableValue(((Red)c).ip)); c.addActionListener(this); } } } return true; } ......//otros comandos del menú } Tabla 4-7. Fragmento de código para el manejo de evento extraído de la clase Estático En la siguiente imagen presentamos el menú de configuración del algoritmo de enrutamiento estático, cualquier opción de configuración seleccionada en este menú será procesada primero por la clase abstracta Algoritmo y luego por la clase Estático: 61 Figura 4-2. Imagen de el menú de configuración de la clase Estático. IV.2.2 Enrutamiento. A continuación se presenta un fragmento de código extraído de la clase Estático, el método encola es utilizado para colocar en la cola de paquetes los paquetes que van llegando al enrutador, aquí es donde el algoritmo Estático realiza el enrutamiento escogiendo la ruta que ha de seguir el paquete, primero se revisa si existe una conexión directa entre el enrutador y la red a la que va dirigido el paquete, sino, el algoritmo busca entre las rutas posibles que existen para dirigir el paquete, sino encuentra la ruta que ha de seguir el paquete, lo envía por la ruta por defecto, para enviarlo a través de otro enrutador el algoritmo transforma el paquete en una cadena anexándole el comando Send al principio, encapsulado dentro de otro enrutador lo envía al enrutador escogido como ruta, así cuando el siguiente enrutador recibe el paquete sabe que debe hacer con el paquete. Paquete[ corrupto=false, ttl=-8, sip=-1062731007, dip=-1062731006, id=0, mf=false, offset=0, size=119, data=SendPaquete[ corrupto=false, ttl=63, sip=-1062731008, dip=-1062730240, id=0, mf=false, offset=0, size=23699, data=null]] Tabla 4-8. Forma de un paquete luego de ser procesado por el enrutador para el envío. . 62 synchronized public void encola(Paquete p,Red r){ Paquete res; Ruta ruta; Red red; Red redes[]=new Red[10]; int i,n; ruta=getRoute(p.dip); if(ruta==null)ruta=por_defecto; n=dueno.redes.size(); dueno.redes.toArray(redes); for(i=0;i<n;i++){ red=redes[i]; if((red.mascara&p.dip)==red.ip){ cola.add(p); sigue.add(red); return; } } for(i=0;i<n;i++){ red=redes[i]; if(ruta!=null){ if((ruta.enrutador&red.mascara)==red.ip){ cola.add(new Paquete(((byte)1), dueno.cantidad_paquetes, Paquete.readableValue(((Integer)dueno.dirip.get(dueno.redes.indexOf(red))).intValue()), Paquete.readableValue(ruta.enrutador),"Send"+p.toString())); sigue.add(red); return; } } } dueno.visu.addEvent("No hay ruta al host: "+Paquete.readableValue(p.dip)); return; } Tabla 4-9. Fragmento que realiza el enrutamiento de paquetes. IV.3 La visualización El enfoque de la visualización como aplicación, es que el usuario debe construir las redes, asignándole la mascara, la dirección IP de cada red, las probabilidades de perder corromper paquetes, el retardo en el envío y la ruta por defecto (gateway), luego se crean los enrutadores, para que funcionen los enrutadores, se les debe asignar un algoritmo de enrutamiento. Se realiza el 63 enlace de los enrutadores con las redes, asignándoles una dirección IP válida(que este en el rango dentro de la red) por cada red en la que se conecte. El usuario puede cambiar los parámetros de las entidades a medida que se ejecuta la visualización, uno de los parámetros que no puede ser cambiado es el algoritmo de enrutamiento, tampoco se deben eliminar redes ni enrutadores. A continuación se presenta un fragmento del trazado de la creación y ejecución de una visualización: Creando un router... Id de componente:0 Seleccionando algoritmo de enrutamiento para el enrutador 0 Algoritmo escogido: Estatico Creando una red.... Id de componente:1 Creando una red.... Id de componente:2 Creando una red.... Id de componente:3 Creando una red.... Id de componente:4 Creando un router... Id de componente:5 Enlazando el enrutador:0 con la red:2 IP asignada: 192.168.1.1 Seleccionando algoritmo de enrutamiento para el enrutador 5 Algoritmo escogido: Estatico Enlazando el enrutador:0 con la red:1 IP asignada: 192.168.0.1 Enlazando el enrutador:0 con la red:3 IP asignada: 192.168.2.1 Creando una red.... Id de componente:6 Enlazando el enrutador:0 con la red:4 IP asignada: 192.168.3.1 Enlazando el enrutador:5 con la red:4 IP asignada: 192.168.3.2 Creando una red.... Id de componente:7 Creando una red.... Id de componente:8 Enlazando el enrutador:5 con la red:8 IP asignada: 192.168.5.1 Enlazando el enrutador:5 con la red:7 IP asignada: 192.168.4.1 64 Enlazando el enrutador:5 con la red:6 IP asignada: 192.168.6.1 Creando un router... Id de componente:9 Creando una red.... Id de componente:10 Creando una red.... Id de componente:10 Creando un router... Id de componente:10 Seleccionando algoritmo de enrutamiento para el enrutador 9 Algoritmo escogido: Estatico Enlazando el enrutador:9 con la red:8 IP asignada: 192.168.5.2 Enlazando el enrutador:9 con la red:2 IP asignada: 192.168.1.2 Seleccionando algoritmo de enrutamiento para el enrutador 10 Algoritmo escogido: Estatico Enlazando el enrutador:10 con la red:4 IP asignada: 192.168.3.3 Enlazando el enrutador:9 con la red:4 IP asignada: 192.168.3.4 Enlazando el enrutador:10 con la red:3 IP asignada: 192.168.2.2 Enlazando el enrutador:10 con la red:7 IP asignada: 192.168.4.2 La red:8 ha enviado el paquete:0 origen:192.168.5.0 destino:192.168.6.0 La red:7 ha enviado el paquete:0 origen:192.168.4.0 destino:192.168.1.0 La red:6 ha enviado el paquete:0 origen:192.168.6.0 destino:192.168.5.0 La red:3 ha enviado el paquete:0 origen:192.168.2.0 destino:192.168.0.0 La red:2 ha enviado el paquete:0 origen:192.168.1.0 destino:192.168.5.0 La red:1 ha enviado el paquete:0 origen:192.168.0.0 destino:192.168.5.0 La red:8 ha enviado el paquete:1 origen:192.168.5.0 destino:192.168.4.0 La red:7 ha enviado el paquete:1 origen:192.168.4.0 destino:192.168.6.0 La red:6 ha enviado el paquete:1 origen:192.168.6.0 destino:192.168.0.0 La red:3 ha enviado el paquete:1 origen:192.168.2.0 destino:192.168.6.0 La red:2 ha enviado el paquete:1 origen:192.168.1.0 destino:192.168.2.0 No hay ruta al host: 192.168.2.0 La red:1 ha enviado el paquete:1 origen:192.168.0.0 destino:192.168.3.0 La red:8 ha enviado el paquete:2 origen:192.168.5.0 destino:192.168.4.0 Tabla 4-10. Trazado de la creación y ejecución de una visualización 65 Figura 4-3. Imagen de la visualización una vez creada. La siguiente imagen muestra la visualización ejecutándose, el trazado de la ejecución está en las páginas anteriores: Figura 4-4. Imagen de la visualización ejecutandose. Para la representación gráfica de los paquetes enviados, corruptos y perdidos se desarrollarón las clases Gráfica y Lienzo, la clase Gráfica hereda de JInternalFrame y contiene un vector de variables booleanas que indican qué gráficas han de ser desplegadas, contiene un objeto de la clase Lienzo que es el encargado de dibujar las gráficas. Los métodos addEnviados, 66 addPerdidos y addCorruptos son utilizados por la clase Visualización para actualizar el lienzo de dibujo. La clase Lienzo contiene las listas de los datos que van a ser representados, haciendo un recorrido secuencial de cada uno de estos datos se van trazando las líneas para representarlos, en esta representación se utiliza Java2D, se crea un objeto GeneralPath al cual se le van anexando los puntos que van a representar las líneas, luego se utiliza el método Draw de la clase Graphics2D, no sin antes asignarle el color correspondiente de cada dibujo. IV.3.1 Errores de Interacción con el Usuario. En esta parte se mostrarán los errores que pueden ser cometidos por el usuario cuando utiliza la aplicación. IV.3.1.1 Error de Asignación de IP. Luego de que se ha cerrado el cuadro de diálogo de asignación de IP, se lanza el proceso para verificar de que no se han cometido errores escribiendo dicha dirección IP, primero se revisa que la dirección este bien escrita (es decir que cumpla con la forma X.X.X.X donde X es un número entre 0 y 255) utilizando el método ipCheck de la clase Paquete, luego se transforma dicha dirección a un entero y se realiza una operación de and lógico a nivel bits entre la máscara y la dirección escrita, para comparar luego si el resultado de esta operación es igual a la dirección, esto con la finalidad de saber si la dirección cumple con la máscara (es decir una IP 192.168.0.1 con una mascara 255.255.255.0 no es válida debido a que al realizar el and el resultado es 192.168.0.0 que es diferente de 192.168.0.1). Es por esto que cuando un usuario crea una red, debe asignar primero la máscara. Luego se busca entre las redes que hay en la visualización para ver si ya hay alguna otra red que este en el rango de direcciones posibles de la red o si esta red cae dentro de las direcciones posibles de otra red. Si se cumplen todos estos requerimientos asignamos la dirección IP escrita por el usuario y actualizamos las direcciones IP de todos los enrutadores conectados a esta red. IV.3.1.2 Error enlazando un enrutador Cuando se va a enlazar un enrutador, se deben cumplir ciertas condiciones. Deben existir redes que tengan asignadas tanto su máscara como su dirección IP, luego de que se logra enlazar el enrutador a una red, se debe verificar que la dirección IP que se asigna al enrutador sea válida 67 siguiendo un proceso muy parecido al descrito para asignar una dirección IP a una red, solo que esta vez el AND lógico se lleva a cabo entre la dirección IP del enrutador y la máscara de la red y comparando el resultado con la dirección IP de la red. Figura 4-5. Imagen de un error de asignación de IP. 68 Capitulo V: Conclusiones y Recomendaciones. Java como lenguaje de programación de objetos presenta grandes ventajas con respecto a los lenguajes tradicionales, debido a que permite una mayor abstracción de los programas desarrollados en este lenguaje, esto aporta una ventaja significativa a la hora de representar entidades reales dentro de una aplicación, contribuyendo así a acelerar el proceso de desarrollo. Los hilos(Threads) facilitan el control de aplicaciones que se deben ejecutar concurrentemente, pues con solo utilizar algunas banderas de la manera adecuada se puede detener y continuar la ejecución de una o varias entidades que se ejecuten en forma concurrente, el único inconveniente es que los métodos resume, stop y suspend tan necesarios para realizar el control, han sido suprimidos. Es por esto que para desarrollar nuestras entidades se utilizó la interfaz Runnable, implementando el método run, de esta interfaz y creando un nuevo hilo por cada entidad a ejecutar. El uso de temporizadores, para ejecutar ciertas partes del código funciona, pero hay que tener en cuenta que si un método requiere mucho tiempo para ejecutarse se producirá un efecto indeseado en cualquier aplicación, que es la acumulación de eventos, si estos eventos tampoco son procesados, el problema crecerá rápidamente y la aplicación podría llegar a colapsar, al ser Java un lenguaje relativamente lento de ejecutar, estos problemas se presentan fácilmente, pero teniendo algunas previsiones (como escribir manejadores de eventos que no requieran tanto tiempo de procesamiento) puede ayudar a evitar estos problemas. El uso de Swing para la creación de la interfaz gráfica de usuario presenta muchas ventajas a la hora del desarrollo, pues su API está muy completa y la abstracción llega más allá, evitando en lo posible la utilización de código nativo para dibujar, que se ve reflejado en una mayor coherencia en lo que respecta a la apariencia en las distintas plataformas. Pero esa ventaja también es su 69 desventaja ya que este nivel de abstracción significa que hay necesidad de cargar un mayor número de clases para dibujar en pantalla, lo que afecta fuertemente el rendimiento de una aplicación. Luego del desarrollo de esta aplicación se ha puesto en entredicho la compatibilidad de Java entre diferentes plataformas, ya que durante las pruebas realizadas hasta el momento no se ha logrado que el programa funcione en Windows 98, a pesar de que tanto en Linux como en Windows 98 se ha utilizado la misma máquina virtual (JVM1.3.0-C). En la representación de los gráficos también existen problemas bajo Linux, entre esos problemas se encuentran la desaparición de las barras de desplazamiento en la clase JScrollPane cuando se mueven las ventanas internas durante la actualización del Lienzo. Solo resta esperar que en futura versiones Sun Microsystems corrija los errores en la maquina virtual que no permiten la correcta ejecución de la aplicación. En cuanto a la aplicación, los objetivos se cumplieron al obtener una herramienta gráfica en la que efectivamente se pueden ingresar técnicas de enrutamiento, siempre y cuando se tenga en cuenta en los algoritmos de enrutamiento que se están ingresando estén bien programados y de su correcto funcionamiento. Tambien estudiar las reglas de extensión de clases que se debe hacer. 70 V.1 Recomendaciones 1.- Esta aplicación se podría convertir en una ayuda a la hora de enseñar cómo funcionan los diferentes algoritmos de enrutamiento. También puede servir como apoyo cuando se construye una nueva red, pues antes de tomar cualquier decisión sobre el enrutamiento se probaría cuan efectiva es, y así evitar los problemas que se suscitarían más tarde por una mala decisión. Otra utilidad de esta aplicación se presenta en el campo de la investigación pues se pondría a prueba los nuevos algoritmos antes de llevarlos a ejecutarse en una red real. 2.- Se debería revisar si las nuevas versiones de la máquina virtual de Java, solucionan algunos de los problemas encontrados durante el desarrollo de la aplicación, así se podría utilizar en otras plataformas diferentes a Linux x86. 3.-Durante el desarrollo de una aplicación gráfica no se debe heredar de las clases del paquete SWING (excepto cuando sea necesariamente obligatorio), pues el hacer esto conlleva a que los objetos incrementen su tamaño haciendo que las aplicaciones requieran más memoria y se ejecuten lentamente (por ejemplo, cuando se crea un nuevo componente). 4.- Hacer las respectivas pruebas de la máquina virtual y la conversión hacia JDK 1.4 o posterior. 71 Bibliografía. • Comer, Douglas E., Redes de Computadoras, Internet e Interredes. Primera Edición. 1997. Prentice – Hall Hispanoamericana, S.A. 506 pags. • Habraken, Joe., Routers Cisco Serie Práctica. 1999. Prentice – Hall. 420 pags. • Forouzan, Behrouz, A., Transmisión de Datos y Redes de Comunicaciones. Segunda Edición. Mc Graw Hill. 2002. 887 pags. • Ford, Merilee., Kim, Jew. H., Spanier, Steve y Stevenson, Tim. Tecnologías de Interconexión de Redes. 1998. Prentice – Hall. 716 pags. • Sánchez A, Jesús., Huecas F, Gabriel., Fernández M, Baltasar y Moreno D, Pilar. Java 2. 2001. Mc Graw Hill. 368 pags. • Schildt, Hebert. Java 2: Manual de Referencia. Cuarta Edición. 2001. Mc Graw Hill. 959 pags. • Ziegler, Bernard P., Praehofer, Herbert y Gon, Kim T. Theory of Modeling and Simulation. Segunda Edición 2000. Academic Press. 510 pags. 72 Anexo #1 Clase Red 73 package org.ula.sistemas; //Clase Red /** * La clase <code>Red</code> se encarga de generar paquetes cada cierto tiempo, para que los enrutadores los procesen. * adem&aacute;s se encarga de transportar los paquetes entre enrutadores. * @see java.awt.event.ActionListener * @see javax.swing.Timer */ import import import import import import import import java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.event.*; java.awt.geom.*; java.util.LinkedList; java.util.Random; java.lang.Runnable; public class Red extends Componente{ int mtu; int gateway=-1; int mascara=0; Timer genera; int genera_paquetes=100; LinkedList enrutadores; int ip=-1; Paquete paquete; public Red(Simulacion s){ super(Simulacion.iconoRed); tipo=Simulacion.RED; ip=-1; simu=s; genera=new Timer(100*simu.escala_tiempo,this); genera.setRepeats(true); genera.stop(); comandos.addFirst("Gateway"); comandos.addFirst("Direcci&oacute;n ip");//0 comandos.addFirst("M&aacute;scara");//1 comandos.addFirst("Retardo generaci&oacute;n");//1 enrutadores=new LinkedList(); createMenu(); }; public Enrutador getGateway(){ if(gateway==-1) return null; return ((Enrutador)enrutadores.get(gateway)); } synchronized public boolean isBusy(){ return paquete!=null; } synchronized public void send(Paquete p){ if(!isBusy()){ paquete=p; if(simu.random.nextInt(max_paq)<perdidos_paq){ paquete=null; paquetes_perdidos++; return; } if(simu.random.nextInt(max_paq)<corruptos_paq){ paquetes_corruptos++; paquete.corrupto=true; } } 74 } public String getInfo(){ String info; info="<center><h3>Informaci&oacute;n de la red</h3></center><font size=\"2\">"; info+="<table border=1><tr><td><b>Direcci&oacute;n IP:</b>"+Paquete.readableValue(ip)+"</td><td>"; info+="<b>Mascara:</b>"+Paquete.readableValue(mascara)+"</td></tr>"; info+="<tr><td><b>Paquetes:</b>"+cantidad_paquetes+"</td><td>"; info+="<b>Bytes transportados:</b>"+cantidad_bytes+"</td></tr>"; info+="<tr><td><b>Paquetes perdidos:</b>"+perdidos_paq+"<br></td><td>"; info+="<b>Paquetes corruptos</b>"+corruptos_paq+"<br></td></tr>"; int gateway=-1; return info; } public void paint(Graphics g){ //Graphics2D g2=(Graphics2D)g; if(enrutadores!=null){ int i,n; Double xclip,yclip,wclip,hclip; Enrutador e; Shape clip=g.getClip(); Rectangle2D rect=g.getClipBounds(); Rectangle union; Area area=new Area(); n=enrutadores.size(); //((Graphics2D)g).draw(getBounds()); //g.setClip(null); for(i=0;i<n;i++){ e=(Enrutador)enrutadores.get(i); area.reset(); union=(Rectangle)getBounds().createUnion(e.getBounds()); union.translate(-getX(),-getY()); area.add(new Area(union)); union=(Rectangle)getBounds(); union.translate(-getX(),-getY()); area.subtract(new Area(union)); union=e.getBounds(); union.translate(-getX(),-getY()); area.subtract(new Area(union)); g.setClip(area); g.setColor(new Color(0,0,255)); g.drawLine(18,18,e.getX()-getX()+18,e.getY()-getY()+18); //g.translate(-Math.abs(getX()-e.getX()),-Math.abs(getY()e.getY())); } g.setClip(clip); } //g.translate(getX(),getY()); super.paint(g); } public void run(){ genera.setDelay(genera_paquetes*simu.escala_tiempo); } public void timerAction(Timer t){ if(t==genera){ //si es el timer de generacion de paquetes Paquete p; Enrutador g; int dip; if(isBusy())return; //si estamos ocupados no podemos enviar if(gateway==-1) return; //si no nos han asignado un gateway dip=simu.getRandomIp(ip); if(dip==0) return; 75 g=getGateway(); p=new Paquete(((byte)255),cantidad_paquetes,ip,dip,simu.random.nextInt(65534)+1); cantidad_paquetes++; cantidad_bytes+=p.size; send(p); }else{ if(paquete!=null){ if(paquete.dip==ip){ //si es para esta red lo desecho paquete=null; return; } //sino lo envio a todos los enrutadores int n,i; n=enrutadores.size(); for(i=0;i<n;i++) ((Enrutador)enrutadores.get(i)).send(paquete,this); paquete=null; } } } /** * M&eacute;todo que implementa las acciones de la Red * tales como enlazar, asignar una direcci&oiacute; ip * asignar una mascara, y seleccionar la puerta de enlace. */ public boolean takeAction(String comando){ int i,n,dip=0,k,l; String dir,mask,respuesta; Red red; Enrutador enru; boolean ban; if(comando=="Enlazar"){ //si el comando es enlazar System.out.println(" "+String.valueOf(ip==1)+"||"+String.valueOf(ip==0)+"||"+String.valueOf(mascara==0)+"||"+"("+String.val ueOf(enrutadores!=null)+"&&"+String.valueOf(enrutadores.contains(this))+")"); if(ip==1||ip==0||mascara==0||(enrutadores!=null&&enrutadores.contains(simu.tothis))){ JOptionPane.showMessageDialog(simu, tohtml("Debes asignar una m&aacute;scara y una ip para enlazar con esta red!!!"), "Error enlace invalido!!!", JOptionPane.ERROR_MESSAGE); return true; } if(enrutadores==null)enrutadores=new LinkedList(); Componente c; do{ dir=(String)JOptionPane.showInputDialog(simu, "<html><body>Escriba la direcci&oacute;n IP del Enrutador en esta red.</body></html>", "IP",JOptionPane.QUESTION_MESSAGE,null,null,Paquete.readableValue(ip)); if(dir!=null){ if(!Paquete.ipCheck(dir)) JOptionPane.showMessageDialog(simu, "<html><body>Debes escribir una ip v&aacute;lida</body></html>", "Error ip no valida!",JOptionPane.ERROR_MESSAGE); else dip=Paquete.ipValue(dir); if(((dip&mascara)!=ip||(dip&(~mascara))==0)){ JOptionPane.showMessageDialog(simu, 76 "<html><body>Debes escribir una ip v&aacute;lida!</body></html>","Error ip no valida!", JOptionPane.ERROR_MESSAGE); dir="255.255.255.255"; } n=enrutadores.size(); for(i=0;i<n;i++){ enru=(Enrutador)enrutadores.get(i); if(enru.dirip.contains(new Integer(dip))&&enru!=simu.tothis){ JOptionPane.showMessageDialog(simu,"<html><body>Esa ip ya esta en uso.</body></html>","Error ip no valida!",JOptionPane.ERROR_MESSAGE); dir="255.255.255.255"; break; } } }else return true; }while(!Paquete.ipCheck(dir)); enrutadores.add(simu.tothis); simu.tothis.redes.add(this); simu.tothis.dirip.add(new Integer(dip)); simu.tothis=null; n=simu.componentes.size(); for(i=0;i<n;i++){ c=((Componente)simu.componentes.get(i)); if(c.getTipo()==simu.ENRUTADOR){ ((JButton)c).setEnabled(true); }else{ ((Red)c).setActionCommand("Menu"); } } simu.repaint(); return true; } if(comando=="Direcci&oacute;n ip"){ do{ dir=(String)JOptionPane.showInputDialog(simu, "<html><body>Escriba la direcci&oacute;n IP de la red</body></html>", "IP",JOptionPane.QUESTION_MESSAGE,null,null,Paquete.readableValue(ip)); if(dir!=null){ if(!Paquete.ipCheck(dir)) JOptionPane.showMessageDialog(simu, "<html><body>Debes escribir una ip v&aacute;lida</body></html>", "Error ip no valida!",JOptionPane.ERROR_MESSAGE); else dip=Paquete.ipValue(dir); if(((dip&mascara)!=dip)){ JOptionPane.showMessageDialog(simu, "<html><body>Debes escribir una ip v&aacute;lida!</body></html>","Error ip no valida!", JOptionPane.ERROR_MESSAGE); dir="255.255.255.255"; } for(i=0;i<simu.redes.size();i++){ red=(Red)simu.redes.get(i); if(red.ip==dip&&red!=this){ JOptionPane.showMessageDialog(simu,"<html><body>Esa ip ya esta en uso.</body></html>","Error ip no valida!",JOptionPane.ERROR_MESSAGE); dir="255.255.255.255"; break; } 77 } }else return true; }while(!Paquete.ipCheck(dir)); n=enrutadores.size(); for(i=0;i<n;i++){ enru=((Enrutador)enrutadores.get(i)); k=enru.redes.indexOf(this); l=((Integer)enru.dirip.get(k)).intValue(); l&=mascara; l|=dip; } ip=dip; return true; } if(comando=="M&aacute;scara"){ do{ mask=(String)JOptionPane.showInputDialog(simu,"<html><body>Escriba la mascara de la red</body></html>","Mascara",JOptionPane.QUESTION_MESSAGE,null,null,Paquete.reada bleValue(mascara)); if(mask!=null||Paquete.maskCheck(mask)){ mascara=Paquete.ipValue(mask); menu.getComponent(0).setEnabled(true); }else if(!Paquete.maskCheck(mask)) JOptionPane.showMessageDialog(simu, "<html><body>Debes escribir una mascara v&aacute;lida</body></html>", "Error ip no valida!", JOptionPane.ERROR_MESSAGE); }while(!Paquete.maskCheck(mask)&&mask!=null); return true; } if(comando=="Retardo generaci&oacute;n"){ do{ ban=false; respuesta=(String)JOptionPane.showInputDialog(this,tohtml("Tiempo de generacion de paquetes en milisegundos"),"Tiempo",JOptionPane.QUESTION_MESSAGE,null,null,String.valueOf(gen era_paquetes)); if(respuesta!=null){ n=respuesta.length(); if(n==0){ ban=true; } else{ for(i=0;i<n;i++){ if(!Character.isDigit(respuesta.charAt(i))){ ban=true; JOptionPane.showMessageDialog(this, tohtml("Debes escribir un entero positivo"), "Error", JOptionPane.ERROR_MESSAGE); break; } } } } }while(ban); if(respuesta==null) ban=true; if(ban==false){ 78 i=Integer.parseInt(respuesta); if(i>0){ genera_paquetes=i; genera.setDelay(simu.escala_tiempo*i); } } return true; } return false; } public void eliminar(){ int n,i,ind,ip; Enrutador e; simu.redes.remove(this); simu.componentes.remove(this); n=enrutadores.size(); for(i=0;i<n;i++){ e=(Enrutador)enrutadores.get(i); ind=e.redes.indexOf(this); e.removeIp(((Integer)e.dirip.get(ind)),this); } setVisible(false); getParent().remove(menu); getParent().remove(this); } public int getTipo(){ return Simulacion.RED; } public boolean isReady(){ return ip!=0&&ip!=-1&&mascara!=0&&enrutadores!=null&&gateway!=-1; } } 79 Anexo #2 Clase Componente 80 package org.ula.sistemas; //Clase abstracta Componente /** * Esta clase se utilizará; para almacenar los objetos que se vayan creando en la visualización, * contiene además los métodos escenciales para manejar cada uno de los componentes de las simulación. * @author Augusto Castillo * @version 0.0.3b */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.awt.geom.*; import java.util.LinkedList; import java.util.Random; import java.lang.Runnable; public abstract class Componente extends JButton implements ActionListener,MouseMotionListener,Runnable,ChangeListener{ /** Contenedor de los componentes de la simulacion.*/ Simulacion simu; /** Comandos que seran mostrados al usuario.*/ protected static LinkedList comandos; /** Icono del componente que implemente esta clase.*/ ImageIcon icono; /** Indica si el componente en estos momentos es movil o no.*/ protected boolean movil=true; /** Variable que indica si este componente esta corriendo.*/ protected boolean running=false; /** Variable que indica si este componente esta en pausa.*/ protected boolean pause=false; /** Cantidad de paquetes que han entrado a este componente*/ protected int paquetes_entrada=0; /** Cantidad de bytes que han entrado a este componente */ protected int bytes_entrada=0; /** Cantidad de paquetes que han salido de este componente */ protected int paquetes_salida=0; /** Cantidad de bytes que han salido de este componente */ protected int bytes_salida=0; /** Cantidad de paquetes que se han perdido en este componente.*/ protected int paquetes_perdidos=0; /** Cantidad de bytes que se han perdido en este componente.*/ protected int bytes_perdidos=0; /** Paquetes que se han corrupto en este componente.*/ protected int paquetes_corruptos=0; 81 /** Total de bytes transportados en los paquetes corruptos.*/ protected int bytes_corruptos=0; /** Cantidad de paquetes que han pasado a traves de este componente.*/ protected int cantidad_paquetes=0; /** Retardo que tienen los paquetes al pasar por este componente.*/ protected int retardo=100; /** Tipo de este objeto, para tomar desiciones con respecto a este.*/ protected static int tipo; /** Temportizador que lleva el control de este componente.*/ protected Timer timer=new Timer(retardo,this); /** Cantidad de bytes que han pasado a traves de este componente.*/ protected int cantidad_bytes=0; /** Generador de numeros aleatorios.*/ protected Random aleatorio=new Random(System.currentTimeMillis()); /** * @see max_paq */ protected int perdidos_paq=1; /** * @see max_paq */ protected int corruptos_paq=1; /** * Establece (perdidos_paq) paquetes perdidos de max_paq paquetes a enviar y * corruptos_paq paquetes corruptos de max_paq paquetes a enviar */ protected int max_paq=1000; //elementos graficos /**Menu que presenta las acciones que se pueden tomar sobre el objeto*/ protected JPopupMenu menu; // aqui estan los constructores Componente(ImageIcon icon){ super(icon); icono=icon; //hacemos que el tiempo de repeticion sea periodico timer.setRepeats(true); timer.stop(); //agremamos los diferentes comandos del menu comandos=new LinkedList(); comandos.add("Retardo"); comandos.add("Informaci&oacute;n");//2 comandos.add("Mover");//3 comandos.add("Pegar");//4 comandos.add("Eliminar");//5 menu=new JPopupMenu(); //creamos el menu //asignamos los diferentes listeners para las acciones setActionCommand("Menu"); //seteamos la accion para que se muestre el menu addChangeListener(this); //el listener de cambios soy yo addActionListener(this); addMouseMotionListener(this); setBounds(10,10,38,38); //todos los componentes deben tener el mismo tamanio 82 setVisible(true); //lo hacemos visible //todas las variable de medicion se inicializan en cero paquetes_perdidos=paquetes_corruptos=bytes_perdidos=bytes_corruptos=cantida d_paquetes=cantidad_bytes=0; } // de aqui en adelante van los metodos generales de la simulacion. /** * Devuelve el tipo de este componente. * @return Simulacion.RED si es una red o Simulacion.Enrutador si es un enrutador. */ public abstract int getTipo(); /** * Asigna un tiempo de retardo a las clases que implementen esta interfaz. * @param tiempo <code>int</code> tiempo en milisegundos que se van a tardar para procesar una transacci&oacute;n. * @return true si ha ocurrido alg&uacute;n error. */ public boolean setDelay(int tiempo){ if(tiempo<=1)return true; retardo=tiempo; timer.setDelay(retardo*simu.escala_tiempo); timer.setDelay(retardo*simu.escala_tiempo); return false; }; /** * Devuelve el tiempo de retardo de las clases que implementen esta interfaz. * @return <code>int</code> el tiempo de retardo de este objeto para procesar un evento,en milisegundos. */ public int getDelay(){ return retardo; }; /** * Inicia la ejecuci&oacute;n de los elementos activos. */ public void inicio(){ setDelay(retardo); timer.start(); running=true; run(); }; /** * Detiene la ejecuci&oacute;n de los elementos activos.<p> * Luego cuando se reinicie la ejecuci&oacute;n tambien lo har&aacute;n las estadisticas. */ public void parada(){ paquetes_entrada=paquetes_salida=bytes_entrada=bytes_salida=paquetes_perdid os=paquetes_corruptos=bytes_perdidos=bytes_corruptos=cantidad_paquetes=cantidad_b ytes=0; timer.stop(); running=false; }; /** * Detiene momentaneamente la ejecuci&oacute;n de los elementos activos. */ public void pause(){ timer.stop(); pause=!pause; 83 }; /** * Le asigna a este objeto una simulacion, de la cual obtendra todos sus datos. * @param s <code>Simulacion</code> contenedor del objeto. */ public void setContenedor(Simulacion s){ simu=s; }; /** M&eacute;todo abstracto para obtener informaci&oacute;n del componente*/ public abstract String getInfo(); //Metodos graficos /** Eliminar el componente y todas las referencias existentes hacia el*/ public abstract void eliminar(); //acciones del componente /**M&eacute;todo heredado de ActionListener, aqui tomamos las primeras decisiones con respecto al objeto*/ public void actionPerformed(ActionEvent ev){ String comando=ev.getActionCommand(),respuesta; int i,n; boolean ban; if(comando==null||comando.length()==0){ timerAction((Timer)ev.getSource()); return; } if(comando=="Menu"){ Point p1=getLocationOnScreen(); p1.x+=18; p1.y+=18; menu.setLocation(p1); menu.setVisible(true); return; } if(!takeAction(comando)){ if(comando=="Informaci&oacute;n"){ JOptionPane.showMessageDialog(simu,tohtml(getInfo())); return; } if(comando=="Mover"){ ((JLayeredPane)getParent()).moveToFront(this); simu.actual=this; movil=true; return; } if(comando=="Pegar"){ movil=false; n=simu.componentes.size(); for(i=0;i<n;i++)((JButton)simu.componentes.get(i)).setEnabled(true); n=simu.menuBar.getMenuCount(); for(i=0;i<n;i++)(simu.menuBar.getMenu(i)).setEnabled(true); simu.actual=null; return; } if(comando=="Eliminar"){ eliminar(); return; } if(comando=="Retardo"){ do{ 84 ban=false; respuesta=(String)JOptionPane.showInputDialog(this,tohtml("Tiempo de retardo en milisegundos"),"Tiempo",JOptionPane.QUESTION_MESSAGE,null,null,String.valueOf(ret ardo)); if(respuesta!=null){ n=respuesta.length(); if(n==0){ ban=true; } else{ for(i=0;i<n;i++){ if(!Character.isDigit(respuesta.charAt(i))){ ban=true; JOptionPane.showMessageDialog(this, tohtml("Debes escribir un entero positivo"), "Error", JOptionPane.ERROR_MESSAGE); break; } } } } }while(ban); if(respuesta==null) ban=true; if(ban==false){ retardo=Integer.parseInt(respuesta); } return; } } } /** * Este m&eacute;todo reviza si la configuracion del objeto esta completa, asi se puede saber si se puede enlazar un enrutador con una red o si se puede ejecutar la visualizaci&oacute;n */ public abstract boolean isReady(); /** * Aqui cada uno de los componentes que implementen la clase deben tomar sus decisiones con respecto al timer. */ public abstract void timerAction(Timer t); /** * Este metodo es el encargado de procesar los comandos no basicos si el comando pasado es no b&aacute;sico regresa true * @param c <code>String</code> comando que se va a ejecutar sobre el objeto. */ public abstract boolean takeAction(String c); /** * M&eacute;todo para mover el componente a travez de la simulaci&oacute;n * arrastandolo. */ public void mouseDragged(MouseEvent ev){ Point p=getLocation(); int i; p.x+=ev.getX()-19; p.y+=ev.getY()-19; 85 setLocation(p); getParent().repaint(); } /** * M&eacute;todo para mover el componente a travez de la simulaci&oacute;n * si este es movil, sino mueve el que sea movil en ese momento. */ public void mouseMoved(MouseEvent ev){ Point p=getLocation(); getParent().repaint(); if(movil){ int i; p.x+=ev.getX()-19; p.y+=ev.getY()-19; setLocation(p); }else{ if(simu.actual!=null){ p.x+=ev.getX()-19; p.y+=ev.getY()-19; simu.actual.setLocation(p); } } } /** * Coloca el menu cuando el componente es colocado en la pantalla. */ public void stateChanged(ChangeEvent e){ getParent().add(menu); Point p=getLocationOnScreen(); p.x+=18; p.y+=18; menu.setLocation(p); simu.ocupa=false; removeChangeListener(this); } /** * Crea el menu contextual del componente. */ public void createMenu(){ JMenuItem item; menu=new JPopupMenu(); int i,n; n=comandos.size(); for(i=0;i<n;i++){ item=new JMenuItem(tohtml((String)comandos.get(i))); item.setActionCommand((String)comandos.get(i)); item.addActionListener(this); menu.add(item); } menu.setSize(menu.getPreferredSize()); menu.setInvoker(this); //menu.setDefaultLightWeightPopupEnabled(true); menu.pack(); } /** * Utilidad para transformar el texto en html. * @param cad <code>String</code> que contiene la cadena a transformar. */ public static String tohtml(String cad){ return "<html><body>"+cad+"</body><html>"; } } 86 Anexo #3 Clase Enrutador 87 package org.ula.sistemas; //Clase enrutador /** * La clase <code>Enrutador</code> es la que permite la comunicaci&oacute;n entre dos redes, una red puede contener uno o m&aacute;s enrutadores * que se encargaran de dirigir el tr&aacute;fico, pero solo uno de ellos actuar&aacute; como un gateway, encargandose de todo el tr&aacute;fico, * este a su vez utilizar&aacute; a los demas enrutadores para completar su tarea.<p> * Esta clase implementa la interface ActionListener para manejar as&iacute; el retardo que debe haber en la simulaci&oacute;n. A su vez utiliza * la clase <code>LinkedList</code> para almacenar todas las redes a las que esta conectado y las ip que tiene en esas redes. * @author Augusto Castillo * @see java.awt.event.ActionListener * @see javax.swing.Timer * @see java.lang.Thread */ import java.awt.*; import java.awt.event.*; import java.util.LinkedList; import java.lang.Runnable; import javax.swing.*; import javax.swing.event.*; import org.ula.sistemas.algoritmos.*; public class Enrutador extends Componente{ public LinkedList redes; public LinkedList dirip; public Algoritmo algoritmo; static int tipo=Simulacion.ENRUTADOR; /** * Crea un enrutador asignandole como contenedor una simulaci&oacute;n s y un tiempo de respuesta delay. * @param s <code>Simulacion</code> contenedor del enrutador. * @param delay <code>int</code> tiempo de respuesta. */ public Enrutador(Simulacion s){ super(Simulacion.iconoRouter); tipo=Simulacion.ENRUTADOR; simu=s; comandos.addFirst("Enlazar"); comandos.addFirst("Seleccionar Algoritmo"); redes=new LinkedList(); dirip=new LinkedList(); createMenu(); } //Implementacion de los metodos de la clase Thread. public void run(){ int i; Red r; Paquete p,ante; /*while(running){ for(i=0;i<redes.size();i++){ r=(Red)redes.get(i); if(r.isBusy()){ p=r.getPaquete(); if(p.dip==((Integer)dirip.get(i)).intValue()){ //si es para mi lo proceso algoritmo.procesa(p); }else{ 88 //si contiene alg&uacute;n broadcast entro aqui sino lo reenvio if((p.dip&255)==255){ //si es para el broadcast de esta red lo proceso tambien if(((p.dip|255)&r.ip)==r.ip){ algoritmo.procesa(p); }else{ //si es para todos los nodos de todas las redes tambien lo proceso if(p.dip==-1){ algoritmo.procesa(p); } } }else{ if(r.getGateway()==this) algoritmo.send(p,r); } } } } }*/ } //Implementacion de los metodos de la interfaz componente. public boolean setDelay(int tiempo){ if(tiempo<=0)return true; retardo=tiempo; return false; } public int getDelay(){ return retardo; } public void removeIp(int ip,Red r){ Integer i=new Integer(ip); dirip.remove(i); redes.remove(r); r.enrutadores.remove(this); } public void removeIp(Integer ip,Red r){ dirip.remove(ip); redes.remove(r); r.enrutadores.remove(this); } public String getInfo(){ int i; String informacion=new String(); if(algoritmo!=null)informacion=informacion+algoritmo.getInfo(); informacion=informacion+"<font size=\"-2\"><center><table border=1><tr><td><h3>N&uacute;mero de Intefaz</h3></td>"+ "<td aling=center><h3>Informaci&oacute;n de la Interfaz</h3></td></tr>"; for(i=0;i<dirip.size();i++){ informacion=informacion+"<tr>"; informacion=informacion+"<td align=\"right\">"+i+"</td>"+"<td align=\"right\">"+(Paquete.readableValue(((Integer)dirip.get(i)).intValue()))+"</ td>"; informacion=informacion+"</tr>"; } paquetes_perdidos=paquetes_corruptos=bytes_perdidos=bytes_corruptos=cantida d_paquetes=cantidad_bytes=0; informacion+="</table><br><table border=1><tr><td align=\"center\"><h3>Paquetes de entrada</h3></td><td align=\"center\"><h3>Paquetes de salida</h3></td><td align=\"center\"><h3>Bytes 89 de entrada</h3></td><td align=\"center\"><h3>Bytes de salida</h3></td><td align=\"center\"><h3>retardo</h3></td></tr>"; informacion+="<tr><td align=\"right\">"+paquetes_entrada+"</td><td align=\"right\">"+paquetes_salida+"</td><td align=\"right\">"+bytes_entrada+"</td><td align=\"right\">"+bytes_salida+"</td><td align=\"right\">"+retardo+"</td></tr>"; informacion=informacion+"</table></center></font>"; return informacion; } public void timerAction(Timer t){ algoritmo.send(); } public boolean takeAction(String comando){ String respuesta; Red r; boolean flag; if(comando=="Seleccionar Algoritmo"){ respuesta=(String)JOptionPane.showInputDialog(this, "Seleccione el algoritmo", "Algoritmo", JOptionPane.QUESTION_MESSAGE, new ImageIcon("images/router.gif"), simu.algoritmos.toArray(), null); if(respuesta!=null){ Class algorithm; try{ if(algoritmo!=null){ menu.remove(algoritmo.menu); } algorithm=Class.forName("org.ula.sistemas.algoritmos."+respuesta); algoritmo=(Algoritmo)algorithm.newInstance(); algoritmo.setDueno(this); }catch(ClassNotFoundException notClass){ notClass.printStackTrace(); JOptionPane.showMessageDialog(simu, tohtml("No existe la clase "+respuesta+ "<br>por favor revise el archivo de configuraci&oacute;n algoritmo.ini"), "Error cargando clase!!!",JOptionPane.ERROR_MESSAGE); }catch(InstantiationException instanEx){ instanEx.printStackTrace(); JOptionPane.showMessageDialog(simu, tohtml("No se logr&oacute; instanciar la clase"+respuesta+ "<br>por favor revise la clase"), "Error cargando clase!!!",JOptionPane.ERROR_MESSAGE); }catch(IllegalAccessException ilegal){ ilegal.printStackTrace(); JOptionPane.showMessageDialog(simu, tohtml("La clase "+respuesta+ "no es p&uacute;blica por favor revise el c&oacute;digo de la clase"), "Error cargando clase!!!",JOptionPane.ERROR_MESSAGE); } } return true; 90 } if(comando=="Enlazar"){ int i,n; Componente c; if(simu.redes==null||simu.redes.size()==0){ JOptionPane.showMessageDialog(simu, tohtml("No hay redes para enlazar!!!"), "Error enlace invalido!!!", JOptionPane.ERROR_MESSAGE); return true; } n=simu.redes.size(); flag=false; for(i=0;i<n;i++){ r=((Red)simu.redes.get(i)); if(r.ip!=1&&r.ip!=0&&r.mascara!=0&&(r.enrutadores==null||!r.enrutadores.contains(this))){ flag=true; } } if(!flag){ JOptionPane.showMessageDialog(simu, tohtml("No hay redes listas para enlazar!!!"), "Error enlace invalido!!!", JOptionPane.ERROR_MESSAGE); return true; } simu.tothis=this; n=simu.componentes.size(); for(i=0;i<n;i++){ c=((Componente)simu.componentes.get(i)); if(c.getTipo()==simu.ENRUTADOR){ ((JButton)c).setEnabled(false); }else{ ((Red)c).setActionCommand("Enlazar"); } } return true; } return false; } //para el test del enrutador public static void main(String argv[]){ JFrame ftest; ftest=new JFrame(); //ftest.getContentPane().setLayout(null); ftest.setBounds(0,0,300,200); JPanel panel=new JPanel(); panel.setLayout(null); Simulacion simu=new Simulacion(); simu.algoritmos.add("Hola"); simu.algoritmos.add("Tonto"); simu.algoritmos.add("Jacobo"); simu.algoritmos.add("Bobo"); Enrutador enru=new Enrutador(simu); enru.dirip.add(new Integer(Paquete.ipValue("192.168.0.1"))); enru.dirip.add(new Integer(Paquete.ipValue("200.44.32.12"))); enru.paquetes_entrada=300; enru.paquetes_salida=260; enru.bytes_entrada=7000; enru.bytes_salida=6800; //System.out.println(enru.getPreferre); 91 ftest.getContentPane().add(panel); panel.add(enru); panel.setVisible(true); ftest.setVisible(true); ftest.getContentPane().setVisible(true); } public int getTipo(){ return Simulacion.ENRUTADOR; } public boolean isReady(){ return redes!=null&&dirip!=null&&algoritmo!=null&&algoritmo.isReady(); } synchronized public void send(Paquete p,Red r){ int miip=(((Integer)dirip.get(redes.indexOf(r))).intValue()); if(((p.dip&miip))==miip){ p.ttl--;//reducimos el tiempo de vida de este paquete algoritmo.procesa(p); }else if(r.getGateway()==this){ p.ttl--;//reducimos el tiempo de vida de este paquete algoritmo.encola(p,r); } } } 92 Anexo #4 Clase ClassLoaded 93 //Clase ClassLoaded para las pruebas de carga de clases //esta clase contiene un metodo ya implementado y uno por implementar para las pruebas abstract class ClassLoaded{ String mensaje1; public ClassLoaded(){ mensaje1="Probando el metodo implementado"; } public String getMensaje1(){ return mensaje1; } public abstract String getMensaje2(); } 94 Anexo #5 Clase Algoritmo 95 package org.ula.sistemas; //Clase abstracta Algoritmo /** * Esta clase abstracta la deben implementar los algoritmos que van a ser usados por los enrutadores * para dirigir los paquetes a su destino.<p> * @author Augusto Castillo * @see Enrutador */ import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.util.*; public abstract class Algoritmo implements ActionListener{ class Ruta{ public int destino; public long retardo_saltos; public long retardo_tiempo; public int enrutador; } public Enrutador dueno; public Hashtable rutas; public LinkedList comandos; public Ruta por_defecto; JMenu menu; public Algoritmo(){ rutas=new Hashtable(); comandos=new LinkedList(); comandos.add("Ruta por defecto"); por_defecto=null; } public void createMenu(){ JMenuItem item; menu=new JMenu("Algoritmo"); int i,n; n=comandos.size(); for(i=0;i<n;i++){ item=new JMenuItem(tohtml((String)comandos.get(i))); item.setActionCommand((String)comandos.get(i)); item.addActionListener(this); menu.add(item); } menu.setSize(menu.getPreferredSize()); } public void setDueno(Enrutador e){ dueno=e; dueno.menu.add(menu); } public abstract void send(); public abstract void encola(Paquete p,Red r); public void procesa(Paquete p,Red r){ if(p.data==null||p.data.length()==0) return; if(p.data=="Get Tables"){ encola(new Paquete(((byte)1),dueno.cantidad_paquetes+1,Paquete.readableValue(((Integer)dueno .dirip.get(dueno.redes.indexOf(r))).intValue()),Paquete.readableValue(p.sip),ruta s.toString()),r); } }; public abstract String getInfo(); public abstract boolean isReady(); public abstract boolean takeAction(String comando); 96 public void actionPerformed(ActionEvent ev){ String comando=ev.getActionCommand(); if(comando=="Ruta por defecto"){ int dip,i,j,m,n; String dir; LinkedList redes=dueno.redes; boolean flag; Red r=null; Enrutador e=null; Integer direccion; if(dueno.dirip==null||dueno.dirip.size()==0){ JOptionPane.showMessageDialog(dueno.simu, tohtml("El enrutador no esta conectado no puedes asignar una ruta por defecto."), "Error ruta no valida!",JOptionPane.ERROR_MESSAGE); return; } dip=(por_defecto==null?0:por_defecto.enrutador); flag=false; do{ dir=(String)JOptionPane.showInputDialog(dueno.simu, tohtml("Escriba la direcci&oacute;n de la ruta por defecto."), "IP",JOptionPane.QUESTION_MESSAGE,null,null,Paquete.readableValue(dip)); if(dir!=null){ if(!Paquete.ipCheck(dir)){ JOptionPane.showMessageDialog(dueno.simu, tohtml("Debes escribir una ip v&aacute;lida"), "Error ip no valida!",JOptionPane.ERROR_MESSAGE); continue; }else dip=Paquete.ipValue(dir); direccion=new Integer(dip); if(dueno.dirip.contains(direccion)){ JOptionPane.showMessageDialog(dueno.simu, tohtml("La ruta por defecto no debe ser el mismo enrutador."), "Error ruta no valida!",JOptionPane.ERROR_MESSAGE); flag=false; }else{ m=redes.size(); for(i=0;i<m;i++){ r=(Red)redes.get(i); if((r.mascara&dip)==r.ip){ n=r.enrutadores.size(); for(j=0;j<n;j++){ e=(Enrutador)r.enrutadores.get(j); if(e.dirip.contains(direccion)){ flag=true; break; } } } if(flag)break; } } }else break; if(!flag){ JOptionPane.showMessageDialog(dueno.simu, 97 tohtml("El enrutador indicado no existe."), "Error ruta no valida!",JOptionPane.ERROR_MESSAGE); } }while(!flag); if(flag){ por_defecto=new Ruta(); por_defecto.destino=-1; por_defecto.retardo_tiempo=r.retardo+e.retardo; por_defecto.retardo_saltos=1; por_defecto.enrutador=dip; } } } /** * Utilidad para transformar el texto en html. * @param cad <code>String</code> que contiene la cadena a transformar. */ public static String tohtml(String cad){ return "<html><body>"+cad+"</body><html>"; } } 98 Anexo #6 Clase Paquete 99 package org.ula.sistemas; import java.lang.String; import java.util.ArrayList; //Clase paquete /** * La clase <code>Paquete</code> permite la comunicaci&oacute;n entre los distintos componentes * de la simulaci&oacute;n a los que se les permite conectarse, as&iacute; la simulaci&oacute;n ser&aacute; * m&aacute;s real y se podr&aactue; tener un mayor control sobre los enrutadores. * <p> * La forma de construir un paquete por un humano es la siguiente: * <p><blockquote><pre> * Paquete p= new Paquete(17,"192.168.0.1","192.168.0.2","hello"); * </pre></blockquote><p> * Esto crear&aacute; un paquete que ser&aacute; enviado desde 192.168.0.1 hasta 192.168.0.2 conteniendo la * cadena &quot;hello&quot;.<p> * La forma de crear un paquete ficticio dentro de la simulaci&oacute;n es la siguiente: * <p><blockquote><pre> * Paquete p= new Paquete(17,0xc0a80001,0xc0a80002,5); * </pre></blockquote><p> * Estas instruciones crear&aacute;n un paquete con un tama&ntilde;o igual a 5, este paquete ser&aacute; enviado * desde 192.168.0.1 hasta 192.168.0.2 y su tiempo de vida ser&aacute; de 17 saltos */ public class Paquete{ /** Indica si el paquete esta corrupto o no*/ protected boolean corrupto; /** Representa el tiempo de vida de este paquete.*/ protected byte ttl; /** Direcci&oacute;n de origen.*/ protected int sip; /** Direcci&oacute;n de destino.*/ protected int dip; /** Identificador de paquete, junto con dip y sip identifican claramente el paquete*/ protected int id; /** Este campo indica si el paquete est&aacute; fragmentado.*/ protected boolean mf; /** Si este paquete est&aacute; fragmentado, este representa el desplazamiento.*/ protected int offset=0; /** Tama&ntilde;o del paquete.*/ protected int size; /** Si este paquete en verdad contiene alguna data ir&aacute; aqu&iacute;.*/ protected String data=null; /** * Constructor para humanos, tambien usado para pasar mensajes entre enrutadores * @param t un <code>byte</code> que representa el tiempo de vida. 100 * @param idp un <code>int</code> que le da la identidad a este paquete. * @param s un <code>String</code> que representa la direcci&oacute;n de origen. * @param d un <code>String</code> que representa la direcci&oacute;n de destino. * @param dat un <code>String</code> que representa la informaci&oacute;n que contendr&aacute el paquete. */ public Paquete(byte t,int idp,String s,String d,String dat){ ttl=t; corrupto=false; sip=ipValue(s); dip=ipValue(d); id=idp; size=dat.length(); data=dat; mf=false; offset=0; } /** * Constructor usado por las redes, para crear paquetes con tama&ntilde;o virtual. * @param t un <code>byte</code> que representa el tiempo de vida. * @param idp un <code>int</code> que le da la identidad a este paquete. * @param s un <code>int</code> que representa la direcci&oacute;n de origen. * @param d un <code>int</code> que representa la direcci&oacute;n de destino. * @param si un <code>int<code> que representa el tama&ntilde;o virtual de el paquete. */ public Paquete(byte t,int idp,int s,int d,int si){ ttl=t; sip=s; dip=d; id=idp; size=si; data=null; } /** * Reduce el tiempo de vida cada vez que sera reenviado este paquete. */ public void send(){ ttl--; } /** * M&eacute;todo de utilidad que comprueba si una mascara esta bien escrita. * @param dirip un <code>String<code> conteniendo la direcci&oacute;n ip. * @return un <code>boolean</code> true si es correcta, false si es incorrecta. */ public static boolean maskCheck(String s){ int i; char c; if(s==null||s.length()<8)return false; s=s.toLowerCase(); for(i=0;i<s.length();i++){ c=s.charAt(i); if(Character.getType(c)!=Character.DECIMAL_DIGIT_NUMBER&&c!='.') return false; } 101 return true; } /** * M&eacute;todo de utilidad que comprueba si una ip esta bien escrita. * @param dirip un <code>String<code> conteniendo la direcci&oacute;n ip. * @return un <code>boolean</code> true si es correcta, false si es incorrecta. */ public static boolean ipCheck(String s){ String pieces[]=new String[4]; int i=0; int index1=0,index2; char c=0; s=s.toLowerCase(); for(i=0;i<s.length();i++){ c=s.charAt(i); if(Character.getType(c)!=Character.DECIMAL_DIGIT_NUMBER&&c!='.') return false; } index2=s.indexOf('.'); i=0; while(index2!=-1&&i<3){ pieces[i]=s.substring(index1,index2); if(pieces[i].length()>3||pieces[i].length()<1||Integer.parseInt(pieces[i])>=255)r eturn false; index1=index2+1; index2=s.indexOf('.',index2+1); i++; } pieces[3]=s.substring(index1); if(pieces[3].length()>3||pieces[3].length()<1||Integer.parseInt(pieces[3])> =255)return false; if(index2!=-1)return false; if(i<3) return false; return true; } /** * M&eacute;todo de utilidad para transformar direcciones ip legibles por humanos * a direcciones ip entendibles por la simulaci&oacute;n.<p> * nota: <font color="red"> no pasar direcciones ip incompletas ejemplo: &quot;150.185.146&quot;</font> * @param dirip un <code>String<code> conteniendo la direcci&oacute;n ip de la forma &quot;192.168.0.1&quot; * @return un <code>int</code> que representa la direcci&oacute;n ip */ public static int ipValue(String dirip){ int valor=0,i; long n=256l*256l*256l; String subs; i=0; while(n!=1){ subs=dirip.substring(dirip.indexOf('.')).substring(1); valor+=Integer.parseInt(dirip.substring(0,dirip.indexOf('.')))*n; dirip=subs; n/=256; i++; } valor+=Integer.parseInt(dirip); return valor; } 102 /** * M&eacute;todo de utilidad para transformar valores en direcciones ip legibles por humanos. * @param dirip un <code>int<code> que representa la direcci&oacute;n ip. * @return un <code>String</code> que contiene la direcci&oacute;n ip legible. */ public static String readableValue(int dirip){ String sub,ip=new String(); int i; sub=Integer.toHexString(dirip); // lo transformamos a hexadecimal for(i=2;i<9;i++) if(sub.length()<i) sub="0"+sub; //le agregamos los ceros que necesitemos for(i=0;i<8;i+=2){ /* * sacamos cada uno de sus componentes en base 16 y los transformamos * a enteros para luego agregarlos a la direccion ip que regresaremos */ ip+=Integer.parseInt(sub.substring(i,i+2),16); if(i!=6)ip=ip+"."; } return ip; } /** * Utilidad para fragmentar paquetes dado un MTU<br> * @param mtu <code>int</code> representa el tama&ntilde;o m&aacute;ximo del paquete. * @param p <code>paquete</code> es el paquete que va a ser fragmentado. * @return <code>Paquete[]</code> un arreglo de paquetes que contienen la data total. * nota: este metodo no toma en cuenta la cabecera ip. */ public static Paquete[] fragmentar(int mtu,Paquete p){ ArrayList generados=new ArrayList(); Paquete pack; int i; if(p.data!=null){ if(p.data.length()>mtu){ for(i=0;i<p.data.length();i+=mtu){ if(i+mtu<p.data.length()){ pack=new Paquete(p.ttl,p.id,p.sip,p.dip,(int)mtu); pack.data=p.data.substring(i,(int)(i+mtu)); pack.mf=true; }else{ pack=new Paquete(p.ttl,p.id,p.sip,p.dip,p.data.length()-i); pack.data=p.data.substring(i,p.data.length()); //si el paquete fragmentado dice que no hay mas framentos //y este es el ultimo framento de ese fragmento entonces //este fragmento dice que no hay mas fragmentos // eso por si reducimos el ancho de banda varias veces if(p.mf)pack.mf=true; else pack.mf=false; } pack.offset=p.offset+i; //le agregamos el offset anterior generados.add(pack); } }else{ for(i=0;i<p.size;i+=mtu){ if(i+mtu<p.size){ pack=new Paquete(p.ttl,p.id,p.sip,p.dip,(int)mtu); pack.mf=true; 103 }else{ pack=new Paquete(p.ttl,p.id,p.sip,p.dip,p.size-i); //si el paquete fragmentado dice que no hay mas framentos //y este es el ultimo framento de ese fragmento entonces //este fragmento dice que no hay mas fragmentos // eso por si reducimos el ancho de banda varias veces if(p.mf)pack.mf=true; else pack.mf=false; } pack.offset=p.offset+i; //le agregamos el offset anterior generados.add(pack); } } } return (Paquete[])generados.toArray(); } public static void main(String argv[]){ System.out.println("La ip es Valida?"+ipCheck(argv[0])); if(ipCheck(argv[0])){ System.out.println(ipValue(argv[0])); System.out.println(readableValue(ipValue(argv[0]))); } } } 104 Anexo #7 Clase Simulación 105 /** * @(#) Simulacion.java */ //Clase Simulacion package org.ula.sistemas; import java.io.*; import java.util.LinkedList; import java.util.Random; import javax.swing.*; import java.awt.event.*; import java.awt.Graphics2D; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.Graphics; /** * La clase <code>Simulacion</code> actua como un contenedor para almacenar todos los componentes */ public class Simulacion extends JFrame{ public static ImageIcon iconoRed=new ImageIcon("images/network.gif"); public static ImageIcon iconoRouter=new ImageIcon("images/router.gif"); protected JMenuBar menuBar; protected JMenu menu; protected JMenuItem menuItem; protected JFileChooser fileChooser; protected String nombreArchivo; protected JButton actual; protected boolean saved; protected boolean ocupa; protected boolean pin; JLayeredPane pane; Enrutador tothis; public static int ENRUTADOR=0,RED=1; /** Factor que representa la escala de tiempo.*/ protected int escala_tiempo; /** Lista de componentes de esta simulaci&oacute;n */ LinkedList componentes; /** Lista de redes para ahorrar tiempo de procesamiento.*/ LinkedList redes; /** Generador de n&uacute;meros aleatorios. */ Random random; LinkedList algoritmos; /** * Construye una Simulaci&oacute;n sin par&aacute;metros. */ public Simulacion(){ //inicializacion de componentes del motor de simulacion componentes=new LinkedList(); redes=new LinkedList(); algoritmos=new LinkedList(); escala_tiempo=1; random=new Random(System.currentTimeMillis()); //inicializacion de componentes del motor grafico saved=true; pane=new JLayeredPane(); menuBar=new JMenuBar(); createMenus(); setJMenuBar(menuBar); fileChooser=new JFileChooser(); setBounds(0,0,640,480); 106 //addMouseMotionListener(this); //addMouseListener(this); setVisible(true); getContentPane().setBounds(0,0,640,480); getContentPane().add(pane); pane.setLayout(null); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); ocupa=false; tothis=null; } /** * Agrega un componente a la simulaci&oacute;n y si es una red lo agrega a la lista de redes. * @param r <code>Red</code> que ser&aacute; agregada a la lista. */ public void add(Componente c){ componentes.add(c); if(c.getTipo()==RED){ redes.add(c); } c.setContenedor(this); pane.add((JButton)c); } /** * Elimina un componente de la simulaci&ocacute;n y si es una red lo elimina de la lista de redes. * @param r <code>Red</code> que ser&aacute; eliminada de la lista. */ public void remove(Componente c){ componentes.remove(c); pane.remove((JButton)c); } public int getRandomIp(int nothis){ int i,n=redes.size(),intentos=0; Red r; do{ r=((Red)redes.get(random.nextInt(n))); if(intentos==5)return 0; intentos++; }while(r.ip==nothis); return r.ip; } /** * Utilidad para agregar colores a los nombres de los campos cuando se solicita la informaci&oacute;n de un objeto. * @param nombre <code>String</code> nombre del campo a colorear * @return <code>String</code> una cadena conteniendo lo siguiente <pre> "<b><font color=blue>"+nombre+":</font></b>";</pre>. */ public static String campo(String nombre){ return "<b><font color=blue>"+nombre+":</font></b>"; } //metodos de la simulacion grafica /** * M&eacute;todo utilizado para crear los menus */ protected void createMenus(){ menu=new JMenu("Archivo"); menu.setVisible(true); menu.add(new AbstractAction("Abrir",new ImageIcon("images/open.gif")){ public void actionPerformed(ActionEvent ev){ int value; 107 if(nombreArchivo==null&&!isSaved()) saveAs(); if(!isSaved()) save(); value=fileChooser.showOpenDialog(Simulacion.this); } }); menu.add(new AbstractAction("Guardar",new ImageIcon("images/save.gif")){ public void actionPerformed(ActionEvent ev){ int value; if(nombreArchivo==null&&!isSaved())saveAs(); else save(); } }); menu.add(new AbstractAction("Salir",new ImageIcon("images/exit.gif")){ public void actionPerformed(ActionEvent ev){ int value; if(nombreArchivo==null&&!isSaved())saveAs(); else{ if(!isSaved()){ value=JOptionPane.showConfirmDialog(Simulacion.this,"Desea salvar antes de salir?","Salir...",JOptionPane.YES_NO_OPTION); if(JOptionPane.NO_OPTION==value) save(); } } System.exit(0); } }); menuBar.add(menu); menu=new JMenu("Componentes"); menu.add(new AbstractAction("Router",new ImageIcon("images/minirouter.gif")){ public void actionPerformed(ActionEvent ev){ JButton imagen; int i,n; n=componentes.size(); for(i=0;i<n;i++)((JButton)componentes.get(i)).setEnabled(false); saved=false; System.out.println("Creando un router...."); n=menuBar.getMenuCount(); for(i=0;i<n;i++)(menuBar.getMenu(i)).setEnabled(false); imagen=new Enrutador(Simulacion.this); add(((Componente)imagen)); pin=true; actual=imagen; } }); menu.add(new AbstractAction("Red",new ImageIcon("images/mininetwork.gif")){ public void actionPerformed(ActionEvent ev){ JButton imagen; int i,n; n=componentes.size(); for(i=0;i<n;i++)((JButton)componentes.get(i)).setEnabled(false); saved=false; System.out.println("Creando una red...."); n=menuBar.getMenuCount(); for(i=0;i<n;i++)(menuBar.getMenu(i)).setEnabled(false); imagen=new Red(Simulacion.this); add(((Componente)imagen)); pin=true; actual=imagen; } }); /*menu.add(new AbstractAction("Enlace",new ImageIcon("images/minienlace.gif")){ 108 public void actionPerformed(ActionEvent ev){ EnlaceGrafico enla; int i; if(!ocupa){ saved=false; System.out.println("Creando un enlace...."); enla=new EnlaceGrafico(Simulacion.this,0,0,0,0); add(enla); //enla.setVisible(true); pin=true; for(i=0;i<componentes.size();i++){ ((JButton)componentes.get(i)).removeMouseListener((MouseListener)componentes.get( i)); ((JButton)componentes.get(i)).removeMouseMotionListener((MouseMotionListener)comp onentes.get(i)); ((JButton)componentes.get(i)).addMouseListener(enla); } pane.addMouseMotionListener(enla); } } });*/ menuBar.add(menu); } public void saveAs(){ int response; response=fileChooser.showSaveDialog(this); if(response==fileChooser.APPROVE_OPTION){ save(); } } public void save(){ File archivo=fileChooser.getSelectedFile(); boolean salvar=false; if(archivo.exists()){ if(nombreArchivo!=null&&nombreArchivo.equals(archivo.getPath())){ salvar=true; }else{ if(JOptionPane.showConfirmDialog(this, "Desea sobreescribir este archivo?", "Sobreescribir?", JOptionPane.YES_NO_OPTION)==JOptionPane.YES_OPTION){ nombreArchivo=archivo.getPath(); salvar=true; }else salvar=false; } }else{ nombreArchivo=archivo.getPath(); salvar=true; } if(salvar){ if(archivo.canWrite()||!archivo.exists()){ //Aqui salvamos saved=true; System.out.println("Salvando "+archivo.getName()); }else{ JOptionPane.showMessageDialog(this, "Disculpe no se puede sobreescribir este archivo!" ,"Error!", JOptionPane.ERROR_MESSAGE); 109 saved=false; } }else saved=false; } public boolean isSaved(){ return saved; } public static void main(String argv[]){ Simulacion s=new Simulacion(); LineNumberReader lector; String cad; try{ lector=new LineNumberReader(new FileReader("config/algoritmos.ini")); do{ cad=lector.readLine(); if(cad!=null)s.algoritmos.add(cad); }while(cad!=null); }catch(Exception ex){ ex.printStackTrace(); System.exit(0); } s.getContentPane().setVisible(true); s.setVisible(true); } } 110