Programación en red en MIDP2.0 |
|
|
En el CLDC Generic Connection Framework, todas las conexiones se crean utilizando el método estático open de la clase Connector. Si no se produce ningún error, este método devuelve un objeto que implementa una de las interfaces definidas en el CLDC Generic Connection Framework e implementadas por MIDP2.0:
La interfaz Connection es el nodo raíz en este arbol de jerarquía por lo que el resto de interfaces serán subinterfaces de Connection. En la figura, los interfaces en un recuadro amarillo son parte de CLDC 1.0. El interfaz HttpConnection fue añadido por MIDP 1.0. Los interfaces dentro de los recuadros azules son interfaces añadidos por MIDP 2.0. Todas estas interfaces estan contenidas en el paquete javax.microedition.io
| |||
|
Esta clase nos ofrece un conjunto de métodos que permiten abrir los distintos tipos de conexiones que definen los interfaces de los que hablamos anteriormente.
El objetivo de tener esta sintaxis, es abstraer al programador de las diferencias que existen entre los diferentes protocolos, de manera que la mayoría del código de una aplicación no se modifica cuando se cambia el protocolo que se está usando. IMPORTANTE: Los ejemplos de conexiones anteriores son sólo ilustrativos. CLDC en sí mismo no proporciona ninguna implementación de ningún protocolo, éstas deben de proporcionarse a nivel de perfil. Además un determinado perfil no tiene porque implementar todos los protocolos. Así por ejemplo MIDP 1.0 sólo proporcionaba una implementación del protocolo HTTP, pero no implementaba ni sockets, ni datagramas (aunque algunos fabricantes pudieran incorporar esta posibilidad). MIDP 2.0 en cambio añade la implementación de protocolos para establecer conexiones HTTP seguras, por Datagramas y mediante Sockets. A continuación vemos los distintos interfaces que implementa MIDP 2.0. | |||
|
HTTP puede implementarse utilizando protocolos IP (como TCP/IP) o protocolos no-IP (como WAP o i-mode), por este motivo se seleccionó como uno de los protocolos para comunicaciones de red en MIDP (en MIDP 1.0 era el único implementado). Todas las implementaciones de MIDP (tanto 1.0 como 2.0) deben soportarlo, garantizando de esta manera la portabilidad de las aplicaciones, que utilizan este protocolo, entre diferentes dispositivos. Se define un nuevo interfaz dentro de la jerarquía del CLDC Generic Connection Framework, el interfaz HttpConnection para el soporte a conexiones HTTP. Este interfaz extiende del interfaz ContentConnection. El protocolo HTTP es un protocolo a nivel de aplicación del tipo petición/respuesta, en el que los parámetros de una petición deben establecerse antes de que se envíe la petición. La conexión puede estar en uno de los siguientes tres posibles estados:
En el interfaz HttpConnection se proporcionan una serie de métodos que pueden invocarse en cada uno de los estados anteriores: En el estado "setup" se pueden invocar los siguientes métodos:
HttpConnection c = (HttpConnection)Connector.open("http://www.it.uc3m.es/pervasive"); c.setRequestMethod(HttpConnection.POST); c.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0"); La transición entre el estado "setup" y el estado "connected" se produce cuando se invoca algún método que precisa enviar o recibir datos al servidor con el que se establece la conexión. Algunos de los métodos que proporciona la implementación del interfaz HttpConnection y que provocan esta transición, son:
A continuación se muestra un ejemplo de código en el que se utiliza la implementación de HttpConnection para leer el contenido de la página http://www.it.uc3m.es/celeste/docencia/cr/hola.txt y mostrarselo al usuario (MIDletHTTPExample.java): import java.io.*; import javax.microedition.midlet.*; import javax.microedition.io.*; import javax.microedition.lcdui.*; /** * Un ejemplo de MIDlet para visualizar el contenido de una URL * utilizando la implementación del interfaz HttpConnection. */ public class MIDletHTTPExample extends MIDlet { private Display display; private String url = "http://www.it.uc3m.es/celeste/docencia/cr/hola.txt"; public MIDletHTTPExample() { display = Display.getDisplay(this); } /** * Método startApp() */ public void startApp() { // Llama al método download para descargar el contenido de la URL try { download(url); } catch(IOException e) { System.out.println("IOException: " + e); } } private void download (String url) throws IOException { StringBuffer b = new StringBuffer(); InputStream is = null; HttpConnection c = null; TextBox t = null; try { long len = 0 ; int ch = 0; // Abre una conexión del tipo HttpConnection c = (HttpConnection)Connector.open(url); // Obtiene un stream de entrada, para leer el contenido de la url // con la que establece la conexión is = c.openInputStream(); // Lee hasta que se cierra la conexión while ((ch = is.read()) != -1) { b.append((char)ch); } // Se contruye un TextBox con el contenido de la URL t = new TextBox("Hola...", b.toString(), 1024, 0); } finally { // Se cierra tanto el stream de entrada if (is != null) is.close(); // Se cierra la conexión if (c != null) c.close(); } // Se visualiza el TextBox en el Display display.setCurrent(t); } /** * pauseApp */ public void pauseApp() { } /** * destroyApp */ public void destroyApp(boolean unconditional) { } } | |||
|
HTTPS es la versión segura del protocolo HTTP y consiste básicamente en establecer conexiones HTTP sobre SSL ( La manera de trabajar con este interfaz es idéntica a la que vimos en el apartado anterior para conexiones HTTP convencionales. La única diferencia es que en este caso utilizaremos un objeto HttpsConnection. Los métodos adicionales que aporta el interfaz HttpsConnection son los siguientes:
Ejemplo de utilización del interfaz HttpsConnection: EjemploHttpSeguro.java Cabe en este punto introducir un nuevo interfaz especificado por MIDP 2.0 : SecurityInfo. Este interfaz, que veremos a continuación, permite acceder a información relativa a conexiones seguras. | |||
|
El interfaz SecurityInfo implementa, como ya se ha dicho, una serie de métodos que permiten acceder a la información asociada a conexiones seguras. Cualquiera de los protocolos que MIDP 2.0 implementa para establecer estas conexiones seguras (Https o sockets seguros sobre ssl) pueden utilizar estos métodos para conocer los parámetros de seguridad de estas conexiones. El API del interfaz SecurityInfo se muestra a continuación:
Ejemplo: // obtener el objeto SecurityInfo asociado a una conexion segura SecurityInfo secInfo = conexionSegura.getSecurityInfo(); // Extraer informacion de seguridad String cipherSuite = secInfo.getCipherSuite(); String protocol = secInfo.getProtocolName(); String version = secInfo.getProtocolVersion(); Certificate certificado = secInfo.getServerCertificate(); | |||
|
El interfaz CommConection define una conexión lógica con un puerto serie. El puerto en cuestión no tiene por qué corresponder a un puerto serie físico sino que puede ser un puerto lógico definido por el sistema operativo. Como corresponde a este tipo de conexiones la información se transmitirá como un flujo de bits en serie. Como ya se dijo anteriormente todos los tipos de conexión existentes se abren utilizando el método open(String URL) de la clase Connector. En este caso el String que debemos pasar como parámetro debe tener el siguiente formato: comm:< identificador del puerto >[< parámetros opcionales >]Los parámetros opcionales son los que definen como será la conexión. Habrá definidos unos valores por defecto que serán aplicados en caso de que no se especifiquen a la hora de establecer la conexión. Los parámetros son los siguientes:
Tanto para establecer la conexión como para especificar los parámetros opcionales que se deseen utilizaremos el método open() de la clase Connector. Para ello el String que pasaremos como argumento debe tener el formato adecuado o de lo contrario se producirá una IllegalArgumentException. Para trabajar con conexiones por puerto serie se implementan, además de los métodos heredados de las interfaces Connection, InputConnection y OutputConnection, dos métodos adicionales:
| ||||||||||||||||||||||||
|
Este interfaz define la abstracción de sockets lo que nos permitirá comunicar distintos procesos entre sí incluso cuando estos se estén ejecutando en distintos dispositivos. Para poder crear un socket necesitaremos un String de conexión genérico que especifique explicitamente un host y un puerto con los que establecer el socket mediante la expresión ya conocida Connector.open(...). Ejemplo: SocketConnection socket = (SocketConnection)Connector.open("socket://< host >:< port >");El interfaz SocketConnection implementa StreamConnection que a su vez proporciona un objeto Connection a la vez que objetos de I/O (un InputStream y un OutputStream) que permiten trabajar con la conexión socket. Cada uno de estos interfaces tiene su propio método close(). Así pues, en sistemas que soporten comunicación duplex, debe ser posible cerrar uno de los sentidos de la comunicación si afectar al otro. La implementación del interfaz SocketConnection define los siguientes métodos:
| |||
|
Este interfaz define una conexión mediante sockets seguros que consiste en una conexión basada en SSL (Secure Socket Layer). Esta conexión segura se establece utilizando Connector.open(..) con un String de conexión genérico que especifique, además de un host y un puerto destino, que dicha conexión debe apoyarse en el protocolo SSL. Ejemplo: SecureConnection secureSocket = (SecureConnection)Connector.open("ssl://< host >:< port >");Si tras llamar al método open no se pudo establecer la conexión debido a algún error relacionado con los certificados de seguridad se lanzará una CertificateException Como subinterfaz de SocketConnection, el interfaz SecureConnection implementará todos los métodos que se expusieron en el apartado anterior. Además de estos implementa el siguiente método:
| |||
|
El interfaz ServerSocketConnection define un socket servidor o pasivo. La finalidad de este tipo especial de sockets es el poder conectar dos sockets establecidos en distintas máquinas de manera que éstas puedan comunicarse entre sí. De no disponer de un socket servidor ambos terminales deberían establecer un socket genérico de forma simultánea, produciéndose un error en caso contrario. Gracias a ServerSocketConnection dispondremos de un servidor que facilita esta labor. El servidor permanecerá escuchando las peticiones de conexión de los clientes (se tratará simplemente del establecimiento de sockets genéricos). Cuando reciba estas peticiones devolverá una instancia de un SocketConnection y la comunicación entre ambos terminales estará establecida. La forma en que el objeto ServerSocketConnection lleva a cabo lo anteriormente explicado es muy sencillo: utiliza el método acceptAndOpen() heredado de la clase javax.microedition.io.StreamConnectionNotifier. Ejemplo: SocketConnection socket = (SocketConnection)serverSocket.acceptAndOpen();En el ejemplo anterior el servidor permanecerá a la espera hasta recibir una petición de conexión SocketConnection dirigida a la máquina y puerto en los que esté escuchando. Una vez recibida la petición el método terminará su ejecución devolviendo la instancia que representa la conexión mediante sockets. El único dato que nos queda por conocer para poder implementar lo hasta ahora visto es cómo crear una instancia de ServerSocketConnection. Para ello utilizaremos, igual que en todos los tipos de conexión vistos hasta ahora, el metodo open() de la clase Connector. La única diferencia respecto a lo visto hasta ahora es que al crear una conexión ServerSocketConnection no se debe especificar el host con el que establecerla ya que será siempre la máquina local: ServerSocketConnection serverSocket = (ServerSocketConnection)Connector.open("socket://:< port number >");Al igual que en los demas tipos de conexiones vistos hasta ahora, podemos omitir el puerto para conseguir una asignación dinámica de un puerto disponible (el sistema gestionará dicha asignación): ServerSocketConnection serverSocket = (ServerSocketConnection)Connector.open("socket://");En este último caso, para conocer el puerto sobre el que se ha establecido la conexión, debemos ejecutar el método getLocalPort() que veremos más adelante. Los métodos disponibles en el interfaz ServerSocketConnection son:
EjemploServer.java, MIDlet ejemplo en el que se establece un socket servidor esperando peticiones de establecimiento de sockets por parte de los clientes (MIDlet que puede ser descargado en el apartado anterior). | |||
|
El interfaz UDPDatagramConnection define una conexión por datagramas de la que se conoce la dirección del punto de terminación ("end point") local. Las características de este tipo de conexión no varían por tratarse de terminales móviles. Al trabajar con el protocolo UDP nos enfrentamos a dos limitaciones inherentes a éste: no se garantiza la entrega y no existe protección frente a duplicados. En comunicaciones sencillas, sin fuertes requisitos de pérdidas o duplicados, las conexiones por datagramas UDP representan un modo eficiente de establecer la comunicación. Sin embargo, en aplicaciones no resistentes frente a pérdidas o duplicados, será necesario trabajar con sockets TCP(utilizando el interfaz ServerSocketConnection que acabamos de ver), penalizando en la cantidad de recursos consumidos (las cabeceras TCP tienen un gran tamaño por lo que el ancho de banda utilizado es mucho menor). Habrá que tener en cuenta entonces cuales son los requisitos de nuestra aplicación para decidirnos por un protocolo u otro estableciendo un compromiso entre fiabilidad y consumo de recursos (en dispositivos limitados como los terminales móviles nos enfrentaremos a nuevas limitaciones). Para obtener una instancia de UDPDatagramConnection recurriremos, como ya es habitual, al método open() de la clase Connector. El formato en el que se debe especificar la dirección para establecer la conexión UDP es el mismo que el utilizado para especificar la dirección destino de un datagrama (utilizando Datagram.setAddress()): Ejemplo: UDPDatagramConnection UDPDat = (UDPDatagramConnection)Connector.open("datagram://< host >:< port >");Los métodos disponibles en el interfaz UDPDatagramConnection son:
| |||
|
Esta clase constituye una novedad de MIDP 2.0 respecto a la versión 1.0 y se encuentra también en el paquete javax.microedition.io. El push registry permite que los MIDlets puedan ser lanzados automáticamente sin necesidad de ser inicializados por el usuario. El concepto de push registry no modifica el ciclo de vida del MIDlet, simplemente introduce dos nuevas vías por las que un MIDlet puede ser activado:
El push registry es parte del sistema gestor de aplicaciones (Application Management System o AMS), que es el software residente en el dispositivo móvil que es responsable del ciclo de vida de cada aplicación (instalación, activación, ejecución y eliminación). Sin embargo, a nivel de programación, es decir, en el propio código del MIDlet, también podremos llevar a cabo actuaciones sobre el push registry. Para ello utilizaremos el API de la clase PushRegistry.
CONEXIONES ESTÁTICAS Y DINÁMICAS. Para habilitar la activación "push" los MIDlets deben utilizar el push registry como ya vimos anteriormente. Se pueden llevar a cabo dos tipos de registros:
El registro de conexiones estáticas ocurre durante la instalación del MIDlet suite. Para ello se deben especificar todas las conexiones a registrar mediantes los atributos MIDlet-Push en el fichero JAD o en el Manifiesto. Cada entrada tendrá el siguiente formato: MIDlet-Push-< n >: < ConnectionURL >, < MIDletClassName >, < AllowedSender > Ejemplo: MIDlet-Push-1: socket://:79, com.sun.example.SampleChat, * MIDlet-Push-2: datagram://:50000, com.sun.example.SampleChat, *Éstas son dos entradas del fichero descriptor que reservarían una conexión socket en el puerto 79 y una conexión por datagramas en el puerto 5000. Por último, hay que tener en cuenta que la instalación del MIDlet suite con declaraciones como las anteriores en el fichero descriptor reserva las conexiones solicitadas para uso exclusivo de los MIDlets dentro de dicho suite. Mientras que éste esté instalado, cualquier intento por parte de otras aplicaciones de abrir una de las conexiones reservadas será rechazado produciendo uno IOException. Si dos MIDlet suites tienen una conexión "push" estática en común no podrán ser instalados simultáneamente y si así sucediera su funcionamiento no sería correcto. REGISTRO DE CONEXIONES DINÁMICAS.EL API DE LA CLASE PushRegistry Para el registro de conexiones "push" dinámicas utilizaremos los métodos de la clase javax.microedition.io.PushRegistry. Son los siguientes: NOTA: El PushRegistry acepta sólo un temporizador por MIDlet. La aplicación debe tener un "TimerTask" para notificar a la aplicación los eventos del temporizador en tiempo. Si intentamos registrar un temporizador que ya está registrado el método devolverá el valor anterior de dicho temporizador, es decir, el instante para el que estaba programada la ejecución del MIDlet. Si es la primera vez que se hace el registro devolverá cero. NOTA IMPORTANTE: Cuando se implemente un MIDlet que al terminar su ejecución registre una alarma para ser activado tras un cierto tiempo, dicho registro debe ser gestionado por un nuevo hilo de ejecución para evitar "dead lock". El motivo es que existe el riesgo de que la ejecución del MIDlet llegue a su fin sin que se haya podido llevar a cabo el proceso de registrar la alarma de activación. Ejemplo de MIDlet que registra una alarma para su activación pasado un tiempo determinado: EjemploPush.java |
No hay comentarios:
Publicar un comentario