Diseño de una Herramienta para Visualizar - Politeca

Anuncio
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ó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á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ón ip");//0
comandos.addFirst("Máscara");//1
comandos.addFirst("Retardo generació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ón de la red</h3></center><font size=\"2\">";
info+="<table border=1><tr><td><b>Direcció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é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á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ó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á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á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ón ip"){
do{
dir=(String)JOptionPane.showInputDialog(simu,
"<html><body>Escriba la
direcció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á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á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á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álida</body></html>",
"Error ip no valida!",
JOptionPane.ERROR_MESSAGE);
}while(!Paquete.maskCheck(mask)&&mask!=null);
return true;
}
if(comando=="Retardo generació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ó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ón.
* @return true si ha ocurrido algú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ón de los elementos activos.
*/
public void inicio(){
setDelay(retardo);
timer.start();
running=true;
run();
};
/**
* Detiene la ejecución de los elementos activos.<p>
* Luego cuando se reinicie la ejecución tambien lo hará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ó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étodo abstracto para obtener informació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é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ó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é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ó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ásico regresa true
* @param c <code>String</code> comando que se va a ejecutar sobre el objeto.
*/
public abstract boolean takeAction(String c);
/**
* Método para mover el componente a travez de la simulació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étodo para mover el componente a travez de la simulació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ón entre
dos redes, una red puede contener uno o más enrutadores
* que se encargaran de dirigir el tráfico, pero solo uno de ellos
actuará como un gateway, encargandose de todo el tráfico,
* este a su vez utilizará a los demas enrutadores para completar su
tarea.<p>
* Esta clase implementa la interface ActionListener para manejar así el
retardo que debe haber en la simulació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ó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ú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úmero de Intefaz</h3></td>"+
"<td aling=center><h3>Informació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ón algoritmo.ini"),
"Error cargando
clase!!!",JOptionPane.ERROR_MESSAGE);
}catch(InstantiationException instanEx){
instanEx.printStackTrace();
JOptionPane.showMessageDialog(simu,
tohtml("No se logró 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ública por favor
revise el có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ó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á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ón entre los
distintos componentes
* de la simulación a los que se les permite conectarse, así la
simulación será
* má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á un paquete que será enviado desde 192.168.0.1 hasta
192.168.0.2 conteniendo la
* cadena "hello".<p>
* La forma de crear un paquete ficticio dentro de la simulación es la
siguiente:
* <p><blockquote><pre>
* Paquete p= new Paquete(17,0xc0a80001,0xc0a80002,5);
* </pre></blockquote><p>
* Estas instruciones crearán un paquete con un tamaño igual a 5,
este paquete será enviado
* desde 192.168.0.1 hasta 192.168.0.2 y su tiempo de vida será 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ón de origen.*/
protected int sip;
/** Direcció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á fragmentado.*/
protected boolean mf;
/** Si este paquete está fragmentado, este representa el
desplazamiento.*/
protected int offset=0;
/** Tamaño del paquete.*/
protected int size;
/** Si este paquete en verdad contiene alguna data irá aquí.*/
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ón de
origen.
* @param d un <code>String</code> que representa la dirección de
destino.
* @param dat un <code>String</code> que representa la informació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ñ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ón de origen.
* @param d un <code>int</code> que representa la dirección de
destino.
* @param si un <code>int<code> que representa el tamañ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étodo de utilidad que comprueba si una mascara esta bien escrita.
* @param dirip un <code>String<code> conteniendo la direcció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étodo de utilidad que comprueba si una ip esta bien escrita.
* @param dirip un <code>String<code> conteniendo la direcció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étodo de utilidad para transformar direcciones ip legibles por
humanos
* a direcciones ip entendibles por la simulación.<p>
* nota: <font color="red"> no pasar direcciones ip incompletas ejemplo:
"150.185.146"</font>
* @param dirip un <code>String<code> conteniendo la dirección ip de
la forma "192.168.0.1"
* @return un <code>int</code> que representa la direcció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étodo de utilidad para transformar valores en direcciones ip
legibles por humanos.
* @param dirip un <code>int<code> que representa la dirección ip.
* @return un <code>String</code> que contiene la direcció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ño má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ón */
LinkedList componentes;
/** Lista de redes para ahorrar tiempo de procesamiento.*/
LinkedList redes;
/** Generador de números aleatorios. */
Random random;
LinkedList algoritmos;
/**
* Construye una Simulación sin pará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ón y si es una red lo agrega a la
lista de redes.
* @param r <code>Red</code> que será 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á 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ó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é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
Descargar