Logo Revista Java

startjavaabout

articles

00. Prólogo (java)
01.a TEMAS INTRODUCTORIOS. (java)
01.b Comandos que Inician la Máquina de Java y la salida de texto (java)
01.c Descripción empírica de la Programación Orientada a Objetos con Java. (java)
01.d Herencia Soportada por Java y Tipos de Datos Básicos. (java)
01.e Operadores, Delimitadores Básicos Y los nombres de función Válidos. (java)
02.a Codificación Inicial y Estructuras de Datos. (java)
02.b Paquetes, y Palabras clave, (Reservadas) (java)
02.c Tipos de Datos, y declaraciones de funciones, Tablas. (java)
02.d Bucles y Tomas de decisión, Excepciones y Control de Errores. (java)
02.e Secuencias de Escape (java)
02.f Concatenación y Conversiones a Texto. (java)
02.g Métodos de Entrada y Salida de datos (java)
02.h Crear Objetos de la biblioteca de Java (java)
02.i Ejercicio: Entrada de Datos y Conversiones (if, try, catch) (java)
02.j Ejercicios, usando excepciones y while, y switch (java)
02.k Práctica complementaria Resuelta sin Arreglos. (java)
02.l Ejercicios de la práctica complementaria (java)
02.m Práctica complementaria resuelta Ej 6 y 7 (java)
02.m Práctica complementaria resuelta Ej 8 y 9 (java)
03.a Métodos estáticos y mecanismos de programación (java)
03.b Arreglos (Arrays o Vectores) (java)
03.c La clase Math como ayudante para resolver problemas (java)
03.d Usando arreglos para un buffer, colas de espera, pilas y listas. (java)
03.e Implementación del buffer tipo FIFO (Cola de espera, el primero es primero en salir) (java)
03.f Implementación del buffer tipo FIFO (Cola de espera, el primero es primero en salir) 2da parte (java)
03.g Implementación del buffer tipo LIFO (La pila, último en llegar es primero en salir) (java)
03.h Implementación del buffer tipo LIFO (La pila, último en llegar es primero en salir) 2da parte (java)
03.i Implementación de una Lista de datos. (java)
03.j Búsqueda Secuencial dentro de la lista de datos. (java)
03.k Búsqueda Aleatoria dentro de la lista de datos. (java)
03.l Búsqueda binaria dentro de una lista ordenada de datos. (java)
03.m Método para Ordenar - La Burbuja (java)
03.n Método para Ordenar - QuickSort Recursivo (java)
03.o Ejercicios Resueltos, ordenar con Java (java)
04.a Nuestro primer Objeto en Java (java)
04.b Codificación del primer Objeto en Java (java)
El ejemplo anterior necesita conocimientos de ejecución paralela de dos procesos, uno para leer del socket (conexión de red) y otro para atender a la telefonista, eso no lo veremos todavía así que....

03.e Implementación del buffer tipo FIFO (Cola de espera, el primero es primero en salir)

(640)
El ejemplo anterior necesita conocimientos de ejecución paralela de dos procesos, uno para leer del socket (conexión de red) y otro para atender a la telefonista, eso no lo veremos todavía así que....
contact
Created,Modified
2009-04-02 11:50:24, 2009-05-07 19:08:48
Author,Nick
Gustavo Guillermo Perez, (madgus) [myblog]

Implementación del buffer tipo FIFO (Cola de espera, el primero es primero en salir)

El ejemplo anterior necesita conocimientos de ejecución paralela de dos procesos, uno para leer del socket (conexión de red) y otro para atender a la telefonista, eso no lo veremos todavía así que cambiaremos el enunciado para implementar esta cola de espera.

La telefonista recibe los teléfonos y tardará solo 1 minuto como máximo por llamada, es decir los números saldrán de a 1 por minuto, pudiendo descansar en el tiempo sobrante, si no hay números esperar, y si hay muchos guardarlos temporalmente.

Utilizaremos una conexión de red, donde la telefonista tendrá un programa en espera que escuchará en la red y la secretaria el que enviará los datos al establecer una conexión.

Telefonista:

gus@gusgus ~$ java com.compunauta.aprendiendojava.Cap3_sock_tel

Escuchando el puerto:4567

Esperando conexión...

Conectado... Esperando teléfonos

Secretaria llamando al tel:123

Secretaria llamando al tel:432

Ultima llamada, nos vamos... programa terminado

gus@gusgus ~$


Secretaria:

gus@gusgus ~$ java com.compunauta.aprendiendojava.Cap3_sock_sec

Intentando conectar con la telefonista

Nos conectamos con la telefonista:127.0.0.1:4567

Ingrese números -1 termina

123

432

-1

Programa terminado

gus@gusgus ~$


Codificación:

Como dijimos antes la implementación y codificación de este ejemplo necesitará de una conexión de red para poder comprender mejor el uso de este tipo de estructuras, no es necesario que dispongamos de una red para llevar a cabo este programa, ya que una PC puede actuar como una red de 1 sola máquina, en este caso usaremos la dirección de red local (loopback) que existe en casi todos los sistemas operativos en los que corre Java. Esta dirección especial, permite conectarse por medio de los protocolos de red a la misma máquina en caso que estemos en un laboratorio de informática y dispongamos de la información de las direcciones ip de las otras PCs de la red sería interesante que se trabajara en grupos de dos, para poder apreciar la conexión remota.

Nota: Queda como tarea para el lector revisar los métodos y propiedades de la clase o tipo de datos Socket y ServerSocket.

Para establecer una conexión de red es necesario que alguien esté escuchando en un puerto, estos puertos son un concepto abstracto que podemos asimilarlo comparándolo con un puerto real donde llegan barcos, dichos barcos una vez que llegan son atendidos y siempre que haya quien atenderlos podrá entrar otro.

En este caso solo esperaremos una única conexión en el puerto, y cuando esta se establezca no esperaremos ninguna otra.

La clase ServerSocket nos permitirá fabricar un objeto que podrá esperar una conexión, y cuando esta llegue podemos abrirla por medio del objeto resultante Socket (conexión). El puerto de escucha en este ejemplo será: 4567, muchos firewalls y mecanismos de protección de red pueden bloquear el acceso a estos puertos, así que cualquier cosa preguntamos al administrador de la red, por otro lado no podemos usar un puerto más bajo inferior a los 1024 porque será necesario por lo general permisos especiales en el sistema operativo.

Telefonista:

  1. package com.compunauta.aprendiendojava;

  2. import java.io.*;

  3. import java.net.*;

  4. /**

  5. * <p>Título: Aprendiendo Java</p>

  6. * <p>Descripción: Ejemplos del Libro Aprendiendo Java de Compunauta</p>

  7. * <p>Copyright: Copyright (c) 2006 www.compunauta.com</p>

  8. * <p>Empresa: COMPUNAUTA</p>

  9. * @author Gustavo Guillermo Pérez

  10. * @version 2006.01.01

  11. */

  12. public class Cap3_sock_tel {

  13. //Declaramos unas variables globales a este tipo de datos

  14. public static int PORT=4567;

  15. public static int BUFF_SIZE=40;

  16. public static int TIMER_SLEEP=60*1000; //60sx1000ms

  17. public static int buff_elem=0;

  18. public static int[] buffer=new int[BUFF_SIZE];

  19.  

  20. public static void main(String[] args) {

  21. //Declaramos la variable socket (será un puntero a objeto)

  22. Socket skt=(Socket)null;

  23. //Declaramos vacío el servidor de sockets para inicializarlo

  24. ServerSocket Ss=(ServerSocket)null;

  25.  

  26. //Tratamos de escuchar el puerto definido por la variable PORT

  27. System.err.println("Escuchando el puerto:"+PORT);

  28. try {Ss = new ServerSocket(PORT);}

  29. catch (IOException ex) {

  30. System.out.println("El sistema no permite abrir el puerto");

  31. System.exit(-1);}

  32.  

  33. //Si no ocurrió error arriba entonces esperamos a la secretaria

  34. System.err.println("Esperando conexión...");

  35. try {skt = Ss.accept();}

  36. catch (IOException ex1) {

  37. ex1.printStackTrace(System.err);

  38. System.exit(-1);}

  39.  

  40. //Si no ocurrió error arriba la secretaria está lista para enviar

  41. System.err.println("Conectado... Esperando teléfonos");

  42. try {

  43. ObjectInputStream datos = new ObjectInputStream(skt.getInputStream());

  44. long timer=0;

  45. boolean timer_on=false;

  46. while (true){

  47. if((skt.isClosed() && (buff_elem<1)) || (buffer[0]==-1)){

  48. //Terminamos el programa si la secretaria terminó

  49. System.err.println("Ultima llamada, nos vamos... terminado");

  50. System.exit(0);

  51. }

  52. //si hay teléfonos los guardamos

  53. if(datos.available()>0){

  54. put_tel(datos.readInt());}

  55. if(timer_on){

  56. //si el timer funciona no hacer nada, si se pasó pararlo

  57. if ((timer+TIMER_SLEEP)<System.currentTimeMillis()){timer_on=false;}

  58. }else{

  59. //Si el timer está apagado, mostramos un tel si es que hay

  60. if (buff_elem>0){System.out.println("Secretaria llamando al tel:"+get_tel());

  61. //Encendemos el timer y guardamos la hora en que empezó

  62. timer_on=true;

  63. timer=System.currentTimeMillis();}

  64. }

  65. //Pausamos 100ms para no sobrecargar el procesador

  66. try {Thread.sleep(100);}

  67. catch (InterruptedException ex3) {}

  68. }//fin del bloque eterno

  69. }catch (IOException ex2) {

  70. ex2.printStackTrace(System.err);

  71. System.exit(-1);

  72. }

  73.  

  74. }//fin del método principal

  75. //Funciones o métodos auxiliares

  76. public static void put_tel(int tel){

  77. //Si se supera el espacio producir un error

  78. if (BUFF_SIZE<(buff_elem+1)){

  79. System.err.println("Buffer overrun: El buffer se llenó demasiado rápido");

  80. System.exit(-1);}

  81. //guardamos el tel y aumentamos en uno el contador

  82. buffer[buff_elem++]=tel;

  83. }

  84. public static int get_tel(){

  85. //almacenamos el primer teléfono

  86. int tel=buffer[0];

  87. //quitamos uno al contador de elementos

  88. buff_elem--;

  89. //recorremos los otros elementos

  90. for (int i=0;i<buff_elem;i++) buffer[i]=buffer[i+1];

  91. //devolvemos el primer teléfono

  92. return tel;

  93. }

  94. }//final de la clase

De las líneas 15 a la 19 se declaran las variables globales que serán accesibles por todos los métodos estáticos de la clase como ser el puerto de escucha, el tamaño del buffer y el verdadero buffer donde utilizamos el tamaño definido para crearlo, recordemos que una vez definido el arreglo que actuará de buffer no podemos expandirlo o reducirlo, por ello el cálculo previo para estimar su máxima cantidad de datos. También se define el tiempo en milisegundos que esperaremos antes de mostrar en pantalla el siguiente teléfono.

A partir de la línea 21 comienza el método principal, el cual se ejecutará paso seguido de inicializar las variables globales. Revisemos la línea 23, la declaración de la variable skt, no estamos inicializando el objeto de la biblioteca, sino que lo estamos apuntando a un objeto especial de tipo nulo, este objeto llamado null es un objeto vacío que no posee propiedades de ningún tipo y cada vez que queramos operar sobre el producirá un error de puntero nulo, entonces ¿porqué lo necesitamos?. El compilador no es lo suficientemente inteligente como para detectar que lo inicializaremos en un bloque de código futuro y necesitamos declararlo en este punto de nuestro método principal, porque todo lo que se declara en bloques especiales como try{}catch(){} es local y desaparece fuera de ellos.

En la línea 25 declaramos el objeto de la biblioteca ServerSocket que escuchará y devolverá un objeto del tipo Socket, usamos el mismo objeto nulo para inicializarlo.

Desde la línea 27 a la 32 intentamos crear el objeto ServerSocket y lo que es más importante, detectar si hubo o no un error por parte del sistema ya que no podremos continuar si se produce un error, como podemos ver en nuestro bloque de control de errores salimos si el sistema no nos permite abrir dicho puerto, en el caso que tengamos algún tipo de protección de red tendremos que desactivarla temporalmente para poder trabajar.

Entre las líneas 34 y 39 nos encargamos de esperar una conexión remota, nuevamente es necesario capturar las posibles excepciones de error que puedan producirse, es obligatorio por el compilador manejar las excepciones declaradas por ServerSocket, como podemos ver, la función accept(); de ServerSocket aceptará una conexión y esa conexión la almacenaremos en el apuntador skt, teniendo ahora correctamente inicializado dicho apuntador podemos usar las características de la conexión.

A partir de la línea 42 comenzamos la operación de lectura de la conexión de red y de la impresión en pantalla de los teléfonos.

Ya habíamos visto los objetos del tipo InputStream para la lectura de texto desde el teclado, en este caso lo usaremos para la lectura desde la conexión, solo que para practicar, utilizaremos un objeto de la misma familia pero del tipo ObjectInputStream que nos permitiría enviar objetos a través del canal o flujo de datos.

El objeto skt provee la función getInputStream(); que nos devolverá el Objeto del tipo InputStream que necesita el objeto de la biblioteca del tipo ObjectInputStream para ser construido.

En la línea 45 declaramos una variable de tipo entero largo (long) timer que utilizaremos para medir el tiempo y así crear nuestro temporizador, le damos un valor inicial.

En la línea 46 declaramos una variable booleana timer_on que nos servirá de bandera para saber el estado del temporizador, si es que está activo (true) o parado (false). Lo inicializamos en parado porque no tenemos teléfonos hasta que la secretaria los comience a escribir.

En la línea 47 se comienza un bloque del tipo “mientras”, while(){} el cual deseamos que sea infinito porque leeremos datos hasta que la secretaria envíe la señal de fin, pero mientras tengamos teléfonos para mostrar en el buffer no podremos dejar de mostrarlos, así que para mejor comprensión del código, el bloque while(true){} se ejecutará por siempre a menos que el programa decida terminar.

Revisemos el código de la línea 48 a la 52, en este bloque comparamos dos condiciones importantes para decidir si el programa debe salir o no, la primera es una condición doble, por eso está encerrada entre paréntesis, es decir si la conexión está cerrada y la cantidad de elementos del buffer es inferior a 1 o sucede que el elemento cero del buffer es el número -1 que indica la secretaria que terminó entonces nos vamos porque es el último elemento y no es necesario mostrarlo.

El siguiente bloque desde la línea 54,55 almacenamos un número entero desde la conexión de red datos, sólo si es que hay datos disponibles, eso lo revisamos con la función available(); que no se quedará esperando, si existen o no datos disponibles de todas maneras el programa sigue su curso.

El timer, entre las líneas 58 a la 65, funciona de la siguiente manera, cuando queremos comenzar a medir el tiempo, almacenamos dentro de la variable timer la hora actual medida en milisegundos, ese dato lo obtenemos con la función del objeto system, currentTimeMillis(), si al timer, le sumamos la cantidad de tiempo que queremos esperar, ese valor siempre será más grande que la hora actual, hasta que se pase el tiempo, eso es lo que comparamos en el bloque if(){}, caso contrario nos preparamos para ver si es necesario encender el timer y mostrar teléfonos, que sólo sucederá si hay más de 1 elemento en el buffer, recordemos que en buff_elem almacenamos la cantidad de elementos de nuestra memoria temporal.

En las líneas 67,68 incluimos otro bloque de control de errores obligatorio porque utilizaremos otra función de la biblioteca de Java que pertenece a la clase Thread (hilo) esa función detiene la ejecución del programa una cierta cantidad de milisegundos, el uso de este pequeño retardo de 100 milisegundos es para no sobrecargar el procesador, ya que estaríamos ejecutando nuestro bucle while(true){} infinidades de veces en 1 único segundo lo cual no es necesario ya que la secretaria no es tan veloz y dejamos libre el procesador para el sistema operativo.

En la línea 69 termina el bloque eterno while(true){} y el bloque de control de errores que lo contiene, dado el caso que se produzca un error dentro del bloque será necesario terminar el programa.

Los métodos auxiliares:

public static void put_tel(int tel){

Esta función agregará un teléfono en la memoria temporal, en nuestro buffer, haciendo una cierta detección de errores, en el caso que el buffer no sea lo suficientemente grande como para almacenar el próximo dato, en este caso el programa se sale con error.

Si esto no sucede, la línea más importante de esta función es:

buffer[buff_elem++]=tel;

Donde como vimos al principio de este libro el signo ++ a la derecha de buff_elem simboliza que primero se utilizará el valor y después se incrementará, entonces en una sola línea representamos las dos operaciones buffer[buff_elem]tel; buff_elem++;

public static int get_tel(){

Esta función extraerá un elemento del buffer, pero al mismo tiempo que lo extrae debe posicionar los demás elementos hacia el inicio del arreglo.

Tampoco hacemos la comprobación de que no haya elementos en el buffer porque la hacemos en el código cada vez que vemos si hay teléfonos para mostrar, aunque deberíamos por buena práctica porque si este es un prototipo y nuestro programa irá creciendo, entonces tal vez se nos escape revisar.

Almacenamos de manera temporal el teléfono próximo antes de recorrer los datos:

int tel=buffer[0];


Después de eso quitamos uno al apuntador de elementos, y lo quitamos antes porque para subir los datos sumaremos uno al índice que recorremos para acomodar los datos y tendríamos que estar revisando que el índice no supere buff_elem-1, como esa condición se compararía cada vez que pasamos por un valor del índice estaríamos ejecutando innecesariamente una resta que podríamos hacer antes.

Una vez terminado devolvemos el teléfono que almacenamos antes que desapareciera.

Nota: Es incorrecto el manejo de error en la función put_tel, ya que en Java existe un modelo de excepciones que deben ser lanzadas y capturadas como en cualquier bloque de control de errores, si no corroboramos el índice Java producirá una IndexOutOfBoundException que de todas maneras terminará el programa.


leavecomment

*Hasta que esta leyenda no desaparezca el libro no ha sido terminado, descarge en pdf:

http://compunauta.com/forums/linux/programacion/java/ebook.html




Aprendiendo Java - Ejemplos resueltos, Ejercicios, prácicas y técnicas de programación con Java #1 - ezine - ©Compunauta - myblog - Anuncios - 1059