Mostrando entradas con la etiqueta Java. Mostrar todas las entradas
Mostrando entradas con la etiqueta Java. Mostrar todas las entradas

Prácticas de Aplicaciones para comunicaciones de red

Pues ya estoy de vuelta en la escuela, y esta vez de nuevo hay una asignatura que me da la oportuindad de escribir código, me refiero a la Aplicaciones para comunicaciones de red (o Redes II, pa' los cuates). Al profe le gusta que hagamos prácticas y pues se me ocurrió otra vez abrir un repositorio de GitHub para publicarlas ahí, además de colaborar con mi compañera de equipo @FannyEvia.

Hasta ahora llevamos un servidor de FTP y un carrito de compras...  sobra decir que son muuuuy sencillas, pero funcionan para conocer el concepto, de ahí se pueden hacer tan complejos como uno desee. Las prácticas son solicitadas en Java o C, así que será lo principal que se pueden encontrar en el repositorio, sin embargo C# también se merece una mención, así que en la medida de lo posible también procuraré hacerlas en ese lenguaje.

Ya saben, pueden mirar el código y preguntar :)


¡Saludos!
@fferegrino :)

Proyectos de Compiladores, ESCOM

Esta vez los saludo con un megapack: los proyectos de la asignatura de Compiladores en la ESCOM, entre ellos un conversor expresión regular-AFN-AFD (Java) y un analizador léxico-sintáctico (C). Y es que por problemas técnicos (y un poco de flojera) no los subí en el tiempo en el que fueron realizados.

La asignatura la cursé con el profesor Juárez Gambino Omar, junto con mi equipo: Cruz Cruz Jorge y Gonzales Rodríguez  Javier (@newbie_geek). A lo largo del semestre aprendí demasiado, y parte de ello fue que había mucho tiempo para practicar lo aprendido, aplicando el conocimiento en varias practicas a lo largo del curso.

La primera, fue un programar un analizador léxico, código y un sencillo reporte el cual coloco a continuación:

La segunda, el conversor de expresión regular a autómata finito no determinista, y de autómata finito no determinista a uno determinista. Este está hecho en Java:

La tercera práctica consistió en utilizar el lenguaje Flex para generar un analizador léxico (muy básico) para C, si ya conocen el lenguaje sabrán que la extensión (por convención) es .l:

Para la cuarta práctica comenzamos a emplear Bison, para ayudarnos en la construcción de un analizador sintáctico, la práctica fue individual, porque en realidad era sencilla. Basarnos en un ejemplo y hacer una calculadora:

La quinta y última práctica fue un analizador léxico y sintáctico para C haciendo uso de Flex y Bison juntos, en teoría es la más complicada, y que requirió más trabajo pero no por eso faltó:

La finalidad de poner estos códigos y reportes como descargables es que tú los puedas checar, leer, tratar de entender y posteriormente implementar a tu modo. No simplemente los descargues y entregues, o lo que es peor, no los bajes y cambies los nombres a las variables (nos gustan los nombres de nuestras variables, no los cambies). Como dicen "allá afuera no vas a encontrar las cosas hechas", así que lo ideal sería que estudies y trates de comprender el código.

Si hay alguna parte que no te queda clara puedes comentarla debajo o enviarme un correo, ya de menos un tuít. Pero hagas lo que hagas, NO COPIES.

¡Saludos!
@fferegrino :)

BluepointerV2



Hace algunos días les contaba de la aplicación Bluepointer que hice para una asignatura en la escuela, hoy he decidido mejorarla para hacerla más útil.

He retirado el control tipo "swipe" y puesto botones en su lugar. Además de añadirle funcionalidad para navegar hasta el inicio o final de la presentación y poder cerrarla desde el dispositivo.

La aplicación la pueden encontrar ya en la tienda Google Play en el siguiente enlace.


Si tienen sugerencias con respecto a la app, no duden en comentárlas.

¡Saludos!
@fferegrino :)

Bluepointer

Bluepointer es un control remoto de diapositivas, usando esta aplicación es sencillo controlar una presentación en Powerpoint. La aplicación se comunica con la PC vía bluetooth. Esta es la tercera y última aplicación que desarrollé para la unidad de aprendizaje Application development for mobile devices (o móviles simplemente) en la ESCOM. 

La idea surgió ya que la sugerencia del profesor era conectar un microcontrolador (a través de un módulo bluetooth) con el teléfono, pero al encontrar dificultades para conseguir el mentado módulo, decidí irme por algo más sencillo ya que para mi lo principal era hacer uso de las capacidades que un dispositivo móvil nos ofrece, como la conectividad.

La aplicación en sí es sencilla, una vez establecida la conexión entre el dispositivo (cliente) y la pc (servidor), lo único que realiza el cliente es enviar "comandos" que resultan ser simples enteros para indicarle al servidor qué acción debe realizar, además, como parte de la funcionalidad extra que me solicitó el profesor, desde el teléfono se pueden enviar mensajes de texto hacia la PC, para lo cual se escribe un arreglo de bytes en el flujo de salida.

Acá un vídeo de la aplicación en todo su esplendor:



Y desde luego, el link hacia la app:


Código fuente de la aplicación para Android (en GitHub): bluepointer-android
Código fuente del servidor (en GitHub): bluepointer-java-server

¡Saludos!
@fferegrino :)

tacOmetro

Cuando el profesor de aplicaciones móviles me comentó sobre la idea de hacer un tacómetro para Android me pareció un poco descabellada la idea, después de mucho pensarlo (y buscar mucho en internet) se pudo, aquí una breve crónica al respecto, además del enlace a la aplicación y el reporte entregado.

Idea

La idea es hacer que mediante la cámara del dispositivo se perciba una imagen, de esta se extraiga la información necesaria como para crear un análisis en las variaciones de ilumnación de la misma. Se parte de la premisa de que cada que un objeto gire frente a la cámara habrá pequeñas (o muy grandes) variaciones en la iluminación. Entonces, contando estas variaciones y el tiempo que se lleva siguiendo podemos obtener la medición de las revoluciones por minuto. Esta parte de la aplicación se puede observar en este vídeo, en él se aprecia como es que la aplicación responde a las variaciones de iluminación:

El dispositivo a medir

Desde el inicio se supo que no podríamos medir cualquier cosa, ya que la prueba se debe desarrollar en ambiente controlado así que agarré mis Legos y de armar se trató esto:

Para finalizar

Ya para terminar les muestro un vídeo del producto funcionando, así como el reporte para que lo descargen y el enlace a la aplicación.

Ah, por cierto, esta la considero una aplicación muerta (ya no piennso seguirla actualizando) así que si alguien lo desea puede obtener el código fuente en GitHub para emplearlo como desee.

Reporte


¡Saludos!
@fferegrino :)

AndroidWebServer

La aplicación

Para construir un servidor web es necesario contar con un programa que haga las veces de “servidor”, es decir, que esté escuchando siempre en uno o varios sockets a la espera de algún cliente para servirle la información solicitada.
La interfaz gráfica será muy sencilla, una etiqueta para mostrar la IP del servidor, un botón para encender o apagar el servidor web y una consola para ver que es lo que está sucediendo, es decir llevar un registro de eventos.

Antes de continuar: Este trabajo está también disponible en versión PDF, lo cual considero, es más cómodo de leer. Lo puedes descargar desde aquí.

Interfaz gráfica

Como se menciona anteriormente, la interfaz es bastante simple, pensando en que de inicio el servidor no es una aplicación que tenga que ser manipulada constantemente por el usuario final.
La interfaz queda abierta a ampliaciones, según se vaya dotando de funcionalidad a esta aplicación.

ServerSocket

Sobre la plataforma Android, el manejo de los sockets es similar al que se realiza en cualquier otra aplicación de escritorio.
Así que simplemente abrimos un ServerSocket
//Fragmento de código del archivo WebServerActivity.java
ServerSocket ss;
try {
    ss = new ServerSocket(puerto);
    while (!isCancelled()) {
        Socket entrante = ss.accept();
//...

Permisos

Para hacer uso de los sockets es necesario otorgar permiso de INTERNET en el manifiesto de la aplicación, lo cual se consigue añadiendo la línea
<uses-permission android:name="android.permission.INTERNET" />
Ya que de otro modo  obtendremos una excepción de IO.

Complicaciones con el manejo de los sockets

En Android no es posible trabajar con sockets en el hilo principal, por tanto no es posible utilizar el código anteriormente mostrado dentro de cualquier método. Por ejemplo, no podemos colocarlo en el método onCreate, ni colocarlo directamente dentro de algún manejador de eventos ya que al tratar de ejecutarlo nos lanzará la excepción:
android.os.NetworkOnMainThreadException
Por tanto es necesario utilizar una clase interna que extienda de AsyncTask para trabajar con el ServerSocket
//Fragmento de código del archivo WebServerActivity.java
public class ServidorWeb
    extends AsyncTask<WebServerActivity, String, Void> {

En cuyo método sobreescrito doInBackground, añadiremos el código necesario para inicializar el socket:
//Fragmento de código del archivo WebServerActivity.java
protected Void doInBackground(WebServerActivity... arg0) {
    try {
        ss = new ServerSocket(puerto);
        while (!isCancelled()) {
            Socket entrante = ss.accept();

Para comenzar la ejecución basta con crear un objeto de nuestra clase nueva, ServidorWeb y llamar al método execute, por la manera en la que se trabajó, al método es necesario pasarle la referencia a la clase de nuestra actividad.
//Fragmento de código del archivo WebServerActivity.java
ServidorWeb servidorWeb;
servidorWeb = new ServidorWeb();
servidorWeb.execute(this);

Registro de eventos

En la interfaz gráfica incluimos un control (View) para llevar el registro de eventos, un símil de consola, pero sin serlo necesariamente, ya que no admite parámetros de entrada ni escritura sobre ella.
Para añadir texto bastaría con llamar al método setText, sin embargo es aquí en donde existe otra limitante de Android, y es que los controles solo pueden ser manipulados directamente por el hilo que los creó, todos los controles son creados por el hilo de UI, y no se pueden modificar por otro sino ese. Recordaremos que los eventos son lanzados desde el servidor, que está en otra clase, y peor aún, corre en otro hilo.
Hacer una llamada como: ServerConsole.append(Html.fromHtml("Buen día señor sol")); desde cualquier otra clase que no sea la de la actividad en cuestión resultará en una excepción:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Para nuestra suerte, existe una solución y es haciendo uso del método onProgressUpdate,con el cual podemos modificar cosas que estén corriendo en el hilo de UI
//Fragmento de código del archivo WebServerActivity.java
@Override
protected void onProgressUpdate(String... values) {
      /* logView es un método implementado en la clase WebServerActivity, en donde fueron creados los controles de la interfas. Se encarga de añadir el texto al control ServerConsole */
      logView((values[0]), level);
}
Contrario a lo que pareciera uno no debe llamar directamente a este método. Si no hacer uso del método (también proporcionado por la clase AsyncTask) publishProgress el cual, a cada llamada, provocará que el método onProgressUpdate se ejecute.
Esa es la manera en la que estaremos modificando la interfaz desde el hilo en el que correrá nuestro servidor.

Apagando y encendiendo el servidor

Para terminar la ejecución del código existente dentro de una AsyncTask tenemos a nuestra disposición el método cancel, del cual nos vamos a valer para apagar el servidor si es que no queremos que siga procesando solicitudes, dada la arquitectura de nuestro servidor, también es necesario cerrar el socket, ya que al estar esperando un cliente, no se apaga de inmediato.
//Fragmento de código del archivo WebServerActivity.java
servidorWeb.cancel(true);
servidorWeb.closeSocket();

Aceptando, leyendo y respondiendo la petición

Una vez que todo el esqueleto esté armado, es necesario adentrarnos a un nivel inferior, al núcleo del servidor, la forma en la que se hace una petición web es aceptando la conexión con un socket creado internamente, a través del cual podemos leer y escribir información al cliente que lo solicite.
Para realizar esto tenemos el siguiente código dentro de doInBackground:
//Fragmento de código del archivo WebServerActivity.java
///Mientras la tarea no haya sido cancelada
while (!isCancelled()) {
      ///Quedamos a la espera de un cliente nuevo
      Socket entrante = ss.accept();
///Actualizamos la “consola” con la información del cliente
///aceptado
      publishProgress("Cliente aceptado: <b>"                                     + entrante.getInetAddress().getHostName() + "</b>",
            "1");
///Usaremos la clase auxiliar PeticionWeb para procesar
      PeticionWeb pw = new PeticionWeb(entrante, this);
///Dado que PeticionWeb extiende de Thread, lo iniciamos
      pw.start();
}

La clase PeticionWeb


//Fragmento de código del archivo PeticionWeb.java
public class PeticionWeb extends Thread {
      private ServidorWeb web;
      privateSocket scliente = null;
Esta clase será el auxiliar encargado de procesar la petición, extiende de Threadpara que corra de manera que no bloquee a las demás peticiones entrantes. En ella se obtienen los flujos de entrada y de salida, que son los canales de comunicación con el cliente que está interesado en consumir de nuestro servidor.
El siguiente código es la implementación sobreescrita de run adaptada a nuestras necesidades.

//Fragmento de código del archivo PeticionWeb.java
@Override
public void run() {
      try {
            /* Obtenemos los flujos de entrada y salida, así como un objeto instancia de PrintWriter para escribir en el cliente */
            BufferedReader in = new BufferedReader(newInputStreamReader(
                        scliente.getInputStream()));
            OutputStream outputStream = scliente.getOutputStream();
            PrintWriter out = new PrintWriter(newOutputStreamWriter(
                        outputStream), true);
            out.flush();

            String cadena = "";
            /* ProcesaPeticion es la clase que usaremos para recuperar el contenido de los archivos almacenados en las carpetas del servidor */
            ProcesaPeticion pp = null;
            /* Leemos del flujo de entrada, mientras la lectura no sea nula continuaremos */
            while ((cadena = in.readLine()) != null) {

                  if (cadena != null ///es
&& !"".equals(cadena)) {
/* La lectura de una línea en blanco marca el final de la petición HTTP */
                        if (cadena.startsWith("GET")) {
                        /* Revisamos el contenido de la cadena que comience con GET, ya que es ahí en donde viene la información del archivo que se desea consultar */
                             cadena = cadena.substring(4);
                  cadena = cadena.substring(0,  
cadena.indexOf(" "));
                             web.log("Petición: " + cadena);
/* Dejamos que la clase auxiliar trate de buscar el archivo y devolver una respuesta */
                             pp = newProcesaPeticion(cadena);
                        }
                  } else
                        break;
            }
/* Escribimos las cabeceras de la respuesta y el contenido solicitado, el cual nos lo devolverá el método getResponse */
            out.println("HTTP/1.0 200 OK");
            out.println("Server: " + web.getIpAddr());
            out.println("Date: " + new Date());
            out.println("Content-Type: text/html");
            out.println("");
            if (pp != null) {
                  out.println(pp.getResponse());
            }
            out.flush();
            out.close();
      } catch (Exception e) {
            web.log("Error en servidor: " + e.toString(), "2");
      }
}

La clase ProcesaPeticion

Esta clase es el puente entre los archivos físicos en el servidor y la respuesta que el cliente espera recibir del servidor, no olvidar que, como estamos guardando los archivos del servidor en la memoria externa del dispositivo necesitamos añadir otro permiso al manifiesto de la app.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
El código:
public class ProcesaPeticion {
      String path;
      String response;

      public ProcesaPeticion(String path) throwsException {
            this.path = path;
            // Checamos si está montada la SD:
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                  // Variables File que nos ayudarán más adelante
                  File sdCard = Environment.getExternalStorageDirectory()
,peticion
,contenedor;
                  // Los documentos deberán existir en la carpeta
                  // "AndroidWebServer/wwwroot"
                  contenedor = new File(sdCard.getAbsolutePath()
                             + "/AndroidWebServer/wwwroot");
                  contenedor.mkdirs();
                  File request = new File(contenedor.getAbsolutePath() + path);
                  StringBuilder strLine = new StringBuilder();
                  if(request.exists() && request.isFile()) {
                        try {
                             // Lectura del archivo
                        } catch (Exception e) {
                        }
                  } else if(request.exists() && request.isDirectory()){
                        // Aquí manejaremos cuando la solicitud sea a un // directorio
                  } else {
                        // La ruta que solicitó no existe
                  }
                  response = strLine.toString();
            } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            } else {
                  throw new Exception("No hay una memoria SD en el dispositivo");
            }
      }
     
}



Referencias

Wikipedia
Documentación de Android Developers



Contacto

Si tienes alguna duda con respecto a la aplicación puedes dejar un comentario en la siguiente liga
Enviarme un correo a antonio.feregrino@gmail.com
Mandarme un tweet a @fferegrino o @IO_Exception
No olvides que la aplicación está disponible en Google Play, la tienda de aplicaciones para Android en la siguiente liga:


¡Saludos!
@fferegrino :)