sábado, 19 de abril de 2014

Programación de Red - JAVA ( 6. Programación de sockets: Más allá de los protocolos estándar)

Contenidos:

  1. Introducción: Como funciona la comunicación en red.
  2. Leyendo desde una URL : Hora de conectar y leer de Internet.
  3. Programar Java para conectar a servidores proxy HTTP.
  4. A descargar contenido de Internet.
  5. Cotización en bolsa: Un programa aplicando lo aprendido.
  6. Programación de sockets: Más allá de los protocolos estándar.

6. Programación de sockets: Más allá de los protocolos estándar.


Esta parte de Java es una de las más emocionantes; o por lo menos eso fue para mi cuando empecé a conocer los Sockets; ya que estos permiten especificar en cierta medida tu propia forma de comunicación entre cliente y servidor. Esta capacidad de poder definir tu forma de comunicación te permite enviar solo los datos necesarios, reduciendo los encabezados o eliminándolos completamente. Como consecuencia la comunicacion por socket es menos pesada que la comunicación con protocolos estandar; ademas la comncicacion por socket es bireccional ( flujo de bites doble); al contrario de lo que sucede en la comunicacion basada en solicitudes y respuestas.

En java tenemos las clases Socket y ServerSocket del paquete java.net para trabajar con socket "normales"; digo normales por que también existe la posibilidad de los Socketc SSL que conectan de forma segura con https y certificados, pero que en este artículo pasaremos de largo sobre el tema...intentaré hablar sobre sockets SSL en otro artículo.

Un socket es una conecxion en un extremo de una red IP. La direccion de un socket contiene una IP y un puerto. Cuando instanciamos la clase ServerSocket se crea un servidor que se ejecuta en memoria y escucha las solicitudes de cliente ( otros programas que se conectarán con Socket ).
El programa cliente debe crear una instancia de Socket ( el socket cliente ) que apunte a la direcciín IP y puerto del ServeSocket que está ejecutándose.

Los puertos recomendados para un ServerSocket son los mayor a 1024 para evitar conflictos con programas del sistema. Algunos puertos conocidos son : 8080 para HTTP, 443 para HTTPS, 21 para FTP, 389 para LDPA, etc.

Para poder intercambiar datos; tanto el cliente como el servidor deben obtener referencias a flujos de entrada y salida. Bueno y ahora vamos a lo nuestro, a lo que nos gusta.....¡¡¡ a programar !!!!

Vamos a ver un ejemplo muy bien comentado escrito en NetBeans donde se programa por un lado el servidor y por otro el cliente. Consiste en que el cliente se conecta al servidor para solicitar un dato, en nuestro ejemplo el precio de un producto. Nuestro servidor buscará el precio y le devuelve el resultado al cliente. Claro que para ejemplo nos bastará con generar un número aleatorio que represente el precio solicitado, en una aplicación real el almacen de datos para obtener el precio podría ser una base de datos de productos

El Servidor:

package com.pelusadev.programacionenlared;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 *
 * @author pelusadev
 */

public class Servidor {

public static void main(String[] arg)
{
     ServerSocket serverSocket;
     Socket cliente;

     BufferedReader entrante = null;
     OutputStream saliente = null;

     try {
          // Creamos el socket server escuchando en el puerto 4000
             serverSocket = new ServerSocket(4000);
             System.out.println("Esperando a que los clientes consulten precios");
             while(true)
             {
                // Esperar la solicitud
                cliente = serverSocket.accept();
                 
                // Obtenemos los flujos
                entrante = new BufferedReader(new InputStreamReader(cliente.getInputStream()));      
                saliente = cliente.getOutputStream();
               
                // Recibimos el nombre del producto que se desea consultar;
                String nombreProducto = entrante.readLine();
        
               // Generamos un precio aleatorio
               Double precioAleatorio = new Double(Math.random()*100);
               String precio = precioAleatorio.toString();
         
               // Escribimos la salida
               byte[] mensajeDeSalida = ("El precio del producto " + nombreProducto + " es "+precio).getBytes();
               saliente.write(mensajeDeSalida);
             }
         } catch (IOException ex) {
             Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
         }finally{
          try{
              entrante.close();
              saliente.close();
          }catch(Exception ex){
              System.out.println("Error en el servidor: " + ex);
          }
        }
   }
}
El Cliente:

package com.pelusadev.programacionenlared;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 *
 * @author pelusadev
 */
public class Cliente {
    
    public static void main(String[] arg)
    {
        OutputStream salida = null;
        BufferedReader entrada = null;
    
        Socket clienteSocket=null;
        
        try{
            // Abrimos una conexión socket cliente
            clienteSocket = new Socket("localhost",4000);
            
            System.out.println("Cliente: " + clienteSocket);
            
            // Obtenemos los flujos
            salida = clienteSocket.getOutputStream();
            entrada = new BufferedReader(new InputStreamReader(clienteSocket.getInputStream()));
            
            // Enviar el nombre del producto al servidor
            salida.write(("GoogleGlass"+"\n").getBytes());
            salida.write(("Final"+"\n").getBytes());
            
            String respuesta;
            while(true)
            {
                respuesta = entrada.readLine();
                if(respuesta.equals("Fin"))
                {
                    break;
                }
                System.out.println("Precio: " + respuesta);
            }
        }catch(UnknownHostException uhe){
            System.out.println("UnknownHostException: " + uhe);
        }catch(IOException ex){
            System.out.println("IOException: " + ex);
        }finally{
            try{
                // Cerramos los flujos
                salida.close();
                entrada.close();
                clienteSocket.close();
            }catch(IOException e){
                System.out.println("No se puede cerrar la conexión: " + e.getMessage());
            }            
        }        
    }
}

Ejecución del servidor:


Ejecución del Cliente


Descárgate la clase Servidor
Descárgate la clase Cliente

Programación de Red - JAVA ( 5. Cotización en bolsa: Un programa aplicando lo aprendido )

Contenidos:

  1. Introducción: Como funciona la comunicación en red.
  2. Leyendo desde una URL : Hora de conectar y leer de Internet.
  3. Programar Java para conectar a servidores proxy HTTP.
  4. A descargar contenido de Internet.
  5. Cotización en bolsa: Un programa aplicando lo aprendido.
  6. Programación de sockets: Más allá de los protocolos estándar.

5. Cotización en bolsa: Un programa aplicando lo aprendido.


En este artículo lo que se pretende es mostrar como consumir información desde internet; en nuestro caso información bursátil proporcionada por yahoo. Podríamos traernos toda la página html e ir desmenuzando el string para quitar las etiquetas html y quedarnos con el dato que nos interesa. De esta forma corremos el riesgo de que si yahoo cambia las etiqueta de su web tendremos que adpatar nuestro código.  Menos mal que estos servicios públicos ofrecen su información en variso formatos (más legible y fáciles de "parsear"). 

Manos a la obra:

Entramos en : http://finance.yahoo; introducimos un símbolo cualquiera, por ejemplo NKE( símbolo bursátil de Nike) y le damos en Get Quote. Nos aparece la cotización en bolsa de Motorola. Nos interesa la URL que aparece en el navegador: http://finance.yahoo.com/q?s=NKE.

Modificamos el código de nuestra clase LectorWebSite vista en el capítulo 2 Leyendo desde una URL : Hora de conectar y leer de Internet.

           url = new URL("http://finance.yahoo.com/q?s=NKE");

Si lo que quieres es quedarte con toda la web; podemos almacenarla en un string:

      String todaLaPagina;
      String textoLeido;
      while(textoLeido = buff.readLine() != null)
      {
        todaLaPagina=todaLaPagina + textoLeido;
      }

Pero como dijimos líneas arriba; esto no es lo más recomendable ya que si yahoo cambia el nombre de los componentes de su web nos veremos obligados a cambiar nuestro código. Por tal motivo usaremos la URL del recurso con la información que necesitamos disponible en formato CSV el que se muestran los valores separados por comas. La dirección en cuestión es:

      http://finance.yahoo.com/d/quotes.csv?s=NKE&f=sl1d1t1c1ohgv&e=.csv

Una vez descargado el fichero esta es la información que contiene:

           MMI,17.10,"4/17/2014","4:03pm",-0.01,17.11,17.26,17.05,15070

Ahora todo se resume a hacer un "split" o usar StringTokenizer para obtener el dato que deseamos.

El código de la clase CotizaciónDeBolsa muestra todo el proceso:


package com.pelusadev.programacionenlared;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.StringTokenizer;

/**
 *
 * @author pelusadev
 */
public class CotizaciónDeBolsa {
    
    /**
     * static void printCotizaciónDeBolsa(String simbolo)
     * 
     * Se declara como método de la clase ( no es necesario instancia
     * un objeto para usar el método ).
     * Como no devuelve nada, solo pinta en pantalla; su valor de retorno
     * es void.
     * Recibe como parámetro un String.
     * 
     * @param simbolo 
     */
    static void printCotizaciónDeBolsa(String simbolo)
    {
       String csvString; // Para guardar la respuesta a la solicitud
       URL url=null; // La url :-).
       URLConnection urlConn=null; // El enlace de comunicación entre nuestra 
                                   //aplicación y una URL 
       InputStreamReader inStream=null; // Para leer flujos de byte a caracter
       BufferedReader buff=null; // Para leer desde el InputStream
       
       try{
           
           url = new URL("http://finance.yahoo.com/d/quotes.csv?s="+simbolo+"&f=sl1d1t1c1ohgv&e=.csv");
           urlConn = url.openConnection();
           inStream = new InputStreamReader(urlConn.getInputStream());
           
           buff = new BufferedReader(inStream);
           
           // Obtenemos la información como cadena
           csvString = buff.readLine();
           
           // Realizamos la descomposición de la cadena que está separada por comas
           // MMI,17.10,"4/17/2014","4:03pm",-0.01,17.11,17.26,17.05,15070
           StringTokenizer tokenizer = new StringTokenizer(csvString,",");
           
           String empresa = tokenizer.nextToken();
           String precio = tokenizer.nextToken();
           String fecha = tokenizer.nextToken();
           String tiempo = tokenizer.nextToken();
           
           System.out.println("Símbolo: " + empresa +
                   "Precio: " + precio + " Fecha: " + fecha + " Tiempo: " + tiempo);
           
       }catch(MalformedURLException emfurl){
           System.out.println("¿Has escrito bien la URL? : esto es lo que escribiste: " + emfurl.toString());
       }catch(IOException eio){
           System.out.println("No se puede leer desde internet: " + eio.toString());
       }finally{
           try{
               inStream.close();
               buff.close();
           }catch(Exception ex){
               System.out.println("CotizaciónDeBolsa no puede cerrar");
           }
       }
    }
    
    public static void main(String[] args)
    {
        printCotizaciónDeBolsa("NKE");
    }
}

Descárgate la clase CotizacionDeBolsa

Siguiente tema:

Programación de Red - JAVA ( 6. Programación de sockets: Más allá de los protocolos estándar).

viernes, 18 de abril de 2014

Programación de Red - JAVA ( 4. A Descargar archivos de Internet )

Contenidos:

  1. Introducción: Como funciona la comunicación en red.
  2. Leyendo desde una URL : Hora de conectar y leer de Internet.
  3. Programar Java para conectar a servidores proxy HTTP.
  4. A descargar contenido de Internet.
  5. Cotización en bolsa: Un programa aplicando lo aprendido.
  6. Programación de sockets: Más allá de los protocolos estándar.

4. A descargar contenido de Internet.



Con lo sabemos hasta ahora acerca de la programación en la red con Java y las técnicas de manejo de ficheros; sobre todo lo que se refiere a abrir correctamente los flujo, podemos ser capaces de descargar cualquier fichero no protegido sin importar el formato(imágenes, vídeo, música, texto, pdf, etc) de Internet. 

El siguiente código se conecta a la página de Scrum ( metodología de desarrollo ágil) y se descarga de esta la guía de Scrum en formato pdf.

package com.pelusadev.programacionenlared;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

/**
 *
 * @author pelusadev
 */
public class DescargarArchivo {
    public static void main(String[] args) {
        
        InputStream in = null;
        FileOutputStream fOut=null;
        
        try{
            URL archivoRemoto = new URL("https://www.scrum.org/Portals/0/Documents/Scrum%20Guides/2013/Scrum-Guide-ES.pdf#zoom=100");
            URLConnection fileStream = archivoRemoto.openConnection();
            
            // Abrimos los flujos E/S
            fOut = new FileOutputStream("manualScrum.pdf");
            in = fileStream.getInputStream();
            
            // Guardar el fichero
            int data;
            while((data=in.read())!=-1)
            {
                fOut.write(data);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            System.out.println("El fichero se ha guardado correctamente");
            try{
                in.close();
                fOut.flush();
                fOut.close();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }    
}
Con esto se guarda el fichero manualScrum.pdf en la raíz del proyecto tal como se muestra en esta captura del IDE NetBeans en la parte izquierda con la vista File de este IDE que nos permite ver la estructura de ficheros de nuestro proyecto.


Descárgate la clase DescargarArchivo.java

Siguiente tema:

Programación de Red - JAVA ( 5. Cotización en bolsa: Un programa aplicando lo aprendido).

Programación de Red - JAVA ( 3. Conectarse a través de servidores proxy HTTP )

Contenidos:

  1. Introducción: Como funciona la comunicación en red.
  2. Leyendo desde una URL : Hora de conectar y leer de Internet.
  3. Programar Java para conectar a servidores proxy HTTP.
  4. A descargar contenido de Internet.
  5. Cotización en bolsa: Un programa aplicando lo aprendido.
  6. Programación de sockets: Más allá de los protocolos estándar.

3. Programar Java para conectar a servidores proxy HTTP



Imaginemos una intranet ( red interna ) de una empresa X que ha instalado un firewall; los empleados como consecuencia de la buena configuración del cortafuegos han perdido la salida a internet e incluso algunos departamentos solo tienen acceso a su propia red interna y no a otras intranets de la empresa. Para que los empleados puedan acceder a Internet se hace uso de los servidores proxy HTTP.

En los navegadores más comunes podemos ver si está protegido por un cortafuegos y los parámetros del servidor proxy en la ficha de opciones avanzadas en el menú Configuración o Preferencias.

Las webs hechas con tecnología Java pueden contener applets que los navegadores utilizan para lanzar solicitudes a servidores remotos a través del firewall; estos applets contiene los parámetros de los servidores proxy.


  • Las aplicaciones Java deben específicar los parámetros del servidor proxy para poder lanzar solicitudes a través del firewall. Para conectar a un servidor llamado http://proxy.pelusadev.com y escuchando en el puerto 8080, debes añadir a tu aplicación los parámetros http.proxyHost y http.proxyPort usando System.setProperty tal como como estas dos líneas:
          System.setProperty("http.proxyHost","http://proxy.pelusadev.com");
          System.setProperty("http.proxyPort","8080");


  • En Java disponemos de la clase java.net.Proxy, con lo cual nuestro código sería el siguiente:
          Proxy miProxy = new Proxy(Proxy.Type.HTTP, 
                                              new InetSocketAddress("http://proxy.pelusadev.com",8080));
          url = new URL("http://www.google.com");
          urlConn = url.openConnection(miProxy);
  • Finalmente si lo que quieres es ejecutar tu aplicación por consola debes pasar los dos parámetros de la siguiente manera. Esto reemplazaría a System.setProperty
          java -Dhttp.proxyHost=http://proxy.pelusadev.com 
           -Dhttp.proxyPort=8080 LectorWebSite

Siguiente tema:

Programación de Red - JAVA ( 4. A descargar contenido de Internet )..

Programación de Red - JAVA ( 2. Leyendo desde una URL : Hora de conectar y leer de Internet )

Contenidos:

  1. Introducción: Como funciona la comunicación en red.
  2. Leyendo desde una URL : Hora de conectar y leer de Internet.
  3. Programar Java para conectar a servidores proxy HTTP.
  4. A descargar contenido de Internet.
  5. Cotización en bolsa: Un programa aplicando lo aprendido.
  6. Programación de sockets: Más allá de los protocolos estándar.

2. Leyendo desde una URL : Hora de conectar y leer de Internet.


Al igual que cuando leemos flujos de archivos locales; lo mismo sucede en la lectura de archivos remoto, la única diferencia es que el flujo se abre en la red. En Java la clase java.net.URL nos permite conectarse a un equipo remoto en Internet y acceder a recurso; siempre y cuando no esté protegido al público.
Se genera MalformedURLException si se especifica una URL incorrecta, por ejemplo si se escribe htp en lugar de http o añade espacios sobrantes. Si se genera MalformedURLException, no indica que el equipo remoto tiene problemas: comprueba la ortografía de la URL La creación del objeto URL no establece una conexión con el equipo remoto; tendrá que abrir un flujo y leerlo. Estos son los pasos a seguir:

  1. Cree una instancia de la clase URL.
  2. Cree una instancia de la clase URLConnection y abra una conexión por medio de la URL del paso 1.
  3. Obtenga una referencia a un flujo de entrada de este objeto mediante la invocación del método URConnection.getInputStream().
  4. Lea los datos desde el flujo. Use un lector en búfer para acelerar el proceso.

A continuación os dejo la clase LectorWebSite que lee el contenido de index.html de google.com:


package com.pelusadev.programacionenlared;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 *
 * @author pelusadev
 */
public class LectorWebSite {
    
    public static void main(String[] args) {
        
        String nextLine;
        URL url = null;
        URLConnection urlConn = null;
        
        InputStreamReader inStream = null;
        BufferedReader buff = null;
        
        try{
            // index.html es un nombre de archivo predeterminado de una URL
            url = new URL("http://www.google.com");
            urlConn = url.openConnection();
            
            inStream = new InputStreamReader(urlConn.getInputStream(),"UTF-8");
            
            buff = new BufferedReader(inStream);
            
            // Leer e imprimir las líneas de index.html
            while(true)
            {
                nextLine = buff.readLine();
                if(nextLine != null)
                {
                    System.out.println(nextLine);
                }else{
                    break;
                }
            }
        }catch(MalformedURLException e){
          System.err.println("Por favor chequea la URL: " + e.toString());
        }catch(IOException e){ 
          System.err.println("No se puede leer desde Internet: " + e.toString());
        }finally{
         if(inStream != null)
         {
          try{
             inStream.close();
             buff.close();
          }catch(IOException e){
           System.err.println("No se puede cerrar los streams: " + e.toString());
          }
         }
       }
    }    
}

Y este es el resulado mostrado en NetBeans:

Programación de Red - JAVA ( 1. Introducción: Como funciona la comunicación en red )

Contenidos:

  1. Introducción: Como funciona la comunicación en red.
  2. Leyendo desde una URL : Hora de conectar y leer de Internet.
  3. Programar Java para conectar a servidores proxy HTTP.
  4. A descargar contenido de Internet.
  5. Cotización en bolsa: Un programa aplicando lo aprendido.
  6. Programación de sockets: Más allá de los protocolos estándar.


1. Introducción



Los equipos conectados a una red pueden comunicarse entre sí solo si acuerdan las reglas de la comunicación mediante protocolos. Estos protocolos definen como se solicitan los datos, si se enviarán en fragmentos, como se reciben los datos, si se amntendrá abierta la conexión, etc. Ejemplos de estos protocolos son : HTTP,TCP/IP,UDP/IP Y FTP.

LAN (Local Area Network, Red de área local) hace referencia a una red informática de dispositivos en un área reducida, ocmo una casa u oficina. Los equipos conectados separados o pertenecientes a diferentes empresas forman parte de una WAN(Wide Area Network, Red de área amplia). Internet está formado por millones de redes y dispositivos. Cuando las redes conectadas pertenencen a la misma organización se denomina intranet, las cuales se protegen con cortafuegos del mundo exterior.

En la Web (WWW) los recursos online se identifican por medio de un localizador uniforme de recursos (URL). Por ejemplo la URL: www.mistercodi.blogspot.com:80/articulo.html afima que existe un archivo denominado articulo.html en el host remoto pelusadev.com y que el programa debe usar el protocolo HTTP para solicitar dicho archivo (recurso); también indica que la solicitud debe enviarse a través del puerto 80.

El nombre del host debe ser exclusivo y se convierte automáticamente a la dirección IP del servidor físico por medio de un ISP(Internet service provider, Proveedor de servicios de internet), es decir nuestra empresa de alojamiento. La IP es un grupo de cuatro cifras, como 122.65.98.11. La mayoria de nosotros tenemos un IP dinámica en nuestros equipos domésticos; pero podemos contratar un IP fija para asignarle a nuestros servidores; así es como se trabaja en el mundo empresarial. Para uso individual basta con una IP asignada dinámicamente siempre que su ISP pueda localizar su servidor resolviendo un nombre de dominio en la dirección IP actual.

Existen varias tecnologíoas en Java que ofrecen intercambio de datos entre equipos de una red. Las clases para la programación de redes se encuentran en el paquete java.net. En ete tutorial aprenderás a usar la clase URL y veremos la programación directa entre conexiones.

Siguiente tema:

Programación de Red - JAVA ( 2. Leyendo desde una URL: Hora de conectar y leer de Internet.).


Snapshot con JavaFX


En este articulo veremos como hacer una "instantánea" con JavaFx 2.2. Es muy práctica la forma de realizar esto con JavaFx versión 2.2; la idea es capturar la imagen en un buffer writer y luego escribir el buffer en un fichero como se hace normlamente en java. Vamos allá:

WritableImage snapshot = stage.getScene().snapshot(null);

Donde "stage.getScene()" es nuestra escena; pero que también podría ser un nodo.

WritableImage snapshot = node.snapshot(null,null);

Luego nos quedaría copiar nuestro WriteableImage a un File dentor de un try catch

File file = new File("test.png"); 
RenderedImage renderedImage = SwingFXUtils.fromFXImage(snapshot, null); ImageIO.write(renderedImage, "png", file);

Finalmente nos quedaría una función así:

public void snapShotJavaFx()
{
  WritableImage snapshot = scene.snapshot(null);
  try{
     File file = new File("test.png");
     RenderedImage renderedImage = SwingFXUtils.fromFXImage(snapshot, null);
     ImageIO.write(renderedImage, "png", file);
  catch(IOException ex){
     Logger.getLogger(TestJavaFX.class.getName()).log(Level.SEVERE, null, ex);
  }
}
Nos quedaría la ventana de JavaFX sin la barra superior de la ventana de windows. Espero les haya servido.