modem GPRS y protocolo TCP/UDP



Para las personas que se inician en el proceso de comunicar dos sistemas mediante modem GPRS, es importante notar , y sobre eso debo hacer mucho enfasis que los modem GPRS, nos proporionan un "tunel" de comunicación , hecho con el protocolo TCP/UDP , cuando tiene implementada esta prestación,  pero aqui la palabra tunel es usado en su mas puro sentido, de algo que permite el paso, mas no efectua en si mismo ninguna operación, esta aclaración obedece a que en muchos de los manuales de los modem GPRS que he utilizado , se habla de manera indiscriminada de TCP/UDP, como un protocolo, un tunel, un servicio y un socket, lo cual desde luego genera mucha confusión.
Quedamos entonces que el el modem genera es un "tunel" de comunicación efectuado con el protocolo TCP/UDP , ojo que no dije y soy claro TCP/IP no TCP/UDP no es lo mismo., ya que en TCP/UDP  es solo el tunel y a cada lado del mismo
debe haber algo que efectua el proceso que necesitamos realizar , que en el caso particular de los modem GPRS, sea un socket (cliente/servidor)
, creado y definido por nosotros ya sea hecho en java, c,c++ ,php o cualquier otro lenguaje que lo permita, o podemos usar un socket pre-definido como puede ser Http, shh, ftp etc , todos desde luego pueden ser declarados como servicios
de arranque automatico al momento del incio del sistema o por el contrario como un servicio de arranque manual, desde luego esto dependera de la necesidad de cada quien, además se debe tener claro que el programa que va aactuar como servidor de socket tiene que tener asignado un número de puerto, que en los servicios "bien conocidos" , que es como se denominan los puertos, del 1-1023 del tipo 22 para ssh, 80 para http , 21 telnet etc, quedan los demas para ser definidos or el usuario.

Toda esta aclaracíon suele tenernos sin cuidado , si estamos usando el modem GPRS, para comunicar dos computadores , pues bastante comuún que una vez establecido el tunel TCP/UDP, por la comunicción del modem GPRS, el uso del programa a ambos extremos de la comunción, sea transparente para nosotros, pues existiran con toda seguridad un servidor http y un navegador al otro extremo con lo cual la dificultad y el concepto de socket, tunel y servicio queda traslapado, pero otra cosa muy distntinta es cuando en el aplicativo que estamos haciendo el "cliente· es un micro-controlador, ya que en este , el procotolo TCP/UDP que el modem brinda sigue , exisitendo, eventualemnte, el socket en el servidor con su número de puerto también , pero el problema es que a menos que tengamos un muy poderoso microcontrolador, lo mas probable es que no tengamos un socket-cliente para el servidor que vamos a usar.

En otras palabras, en general , no basta simplemente mandar a travs del modem un "hola mundo", para que todo funcione, pues el servidor , no solo espera la informaciíon de acuerdo al protocolo TCP/UDP, sino que además debe cumplirse con todos los requerimientos usados en el protocolo implementado en el socket, por ejemplo para comunicarnos por un servidor htpp (como vimos anteriormente en el articulo conexion modem GPRS socket TCP/UDP ), debemos usar los comandos y cabecra propios de http , llamado GET , y si es ssh, debemos conocer los comandos y cabeceras que hay que enviar para invocar el ssh y poder usarlo correctamente.

En estos casos casi que es obligatorio crearnos nuestros propios socket cliente-servidor con los protocolos y cabeceras que concideremos adecuados

Cuando nos embarcamos en la creacion de nuestro propio servidor-cliente de socket, debemos tener muy claro lo que esperamos de él, si vamos a tener alto trafico sobre el mismo no olvidar , cerrar los socket que no se estan usando y en lo posible utilizar hilos , para poder procesar las peticiones adecuadamente.


Si se esta desarrollando el servidor-cliente de socket, para java, debemos tener en cuenta que java tiene implementado la escritura y lectura de datos en el socket mediante stream, (ImputStream y Outputstream) y la comunicacion entre el cliente y el socket se hace mediante estos procedimientos , lo que implica que si se esta trabajando con un microcontrolador en el cual no se puede cargar el socket cliente java, no tendremos la posiblidad de usar de manera directa, ya que lo usual sería enviar datos por un puerto seruial (uart) convencional, por lo tanto el modelo cliente-serviodr se tendrá necesariamente que ajustar mediante modelos de envio de objetos,  arreglos de caracters etc. de lo contrario el servidor no es capaz de entender los datos que se le están enviando aunque le estén llegando.

No olvidar además abrir el puerto en el cual firewall del servdor va recibir las peticiones

El siguiente programa es un servidor-cliente trivial 

Servidor.java
------------------------------------------------------------------------------------------------------------------
import java.io.*   ;
import java.net.*  ;
class Servidor
  {
  //Se recomienda usar un puerto fuera de los bien conocidos 
  // o sea superior (0-1024)

  static final int PUERTO=5000;

  public Servidor( )
    {
    StringBuffer mensaje = new StringBuffer() ;
    try {
          ServerSocket skServidor = new ServerSocket(PUERTO)         ;
          System.out.println("Escuchando el puerto " + PUERTO )          ;

          //Bucle que permite atender 100 usuarios, lo ideal es crear
          //un bucle infinito , pero procesando hilos. si se va hacer un uso
          // intenso del servidor

          for ( int numUsr = 0; numUsr< 100 ; numUsr++ )
             {
                Socket skCliente = skServidor.accept()                               ;

               //Muestra en la consola del servidor cuando un usuario se conecta

                System.out.println("Atendiendo usuario " + numUsr)         ;


                OutputStream salida = skCliente.getOutputStream()         ;
                DataOutputStream flujoOut= new DataOutputStream( salida ) ;
                flujoOut.writeUTF( "Bienvenido " + numUsr )                    ;
                flujoOut.flush()                                                                     ;
                flujo.close()                                                                          ;

               //El uso de estas instrucciones dependerán del tipo de cliente
               //que se este usando , con un cliente java funciona sin problema
               //con un cliente serial (uart) texto plano, puede variar dependendo
               //de implementació a usar ObjectInputStream o ArrayInputStream
             
                InputStream entrada     = skCliente.getInputStream()             ;
                DataInputStream flujoIn = new DataInputStream( entrada )  ;
            
                //Notar el uso de readUTF y writeUTF, que permite el la comunicación
                //entre cliente y servidor java se independiente de la plataforma y
                //sistema operativo

                mensaje.append(flujoIn.readUTF().toString())              ;

                //Muestra en la consola del servidor los datos recibidos
                System.out.println(mensaje)                                          ;
       
                OutputStream salida1 = skCliente.getOutputStream()         ;
                DataOutputStream flujoOut1= new DataOutputStream( salida1 );

               // Regresa al cliente el mensaje de que los datos fueron recibidos
                flujoOut1.writeUTF( "Datos procesados ok "  )              ;
                flujoOut1.flush()                                                              ;
                flujoOut1.close()                                                              ;
         
                //Cierra el socket después de procesar la información
                skCliente.close();
             }
          System.out.println("Demasiados usuarios atendidos");
        }
    catch( Exception e )
        {
           System.out.println( e.getMessage() );
        }
      }

  public static void main( String[] arg )
    {
      new Servidor();
    }
}

--------------------------------------------------------------------------------------------------------------

Cliente.java
--------------------------------------------------------------------------------------------------------------
import java.io.*;
import java.net.*;

class Cliente
      {

       static final String HOST = "localhost";

       // Habilitar el puerto asociado al servidor, recordar dar salida
      // el firewall tipo tcp al puerto seleccioando.

       static final int PUERTO=5000;
       public Cliente( ) {
       try{
            Socket skCliente = new Socket( HOST , PUERTO );
            InputStream aux = skCliente.getInputStream();
            DataInputStream flujo = new DataInputStream( aux );

            System.out.println( flujo.readUTF() );
            skCliente.close();
          }
        catch( Exception e )
         {
           System.out.println( e.getMessage() );
         }
}

public static void main( String[] arg )
      {
        new Cliente();
      }
}
--------------------------------------------------------------------------------------------------------------


Si se pretende hacer una conexion por un puerto IP , con protocolo Http, es decir apache o tomcat por ejemplo puertos (80 y 8080 respecivamnt), hay que saber algunas cosas importantes,  si se esta haciendo una conexion or una apliación que no sea un navegador, por ejemplo un script en PHP, incluso en Java o C. o desde un microcontrolador.

Como estos script no son navegadores se debe implementar un codigo donde se
haga uso de los comandos de Http , como GET y POST por ejemplo, si se desea enviar unos parametros a un servidor que sea http , la cadena del comando pasado a el puerto serie del modem podria ser

GET /?parametros=hola<SPACE>mundo<CR><LF><CR><LF>

A destacar en esta linea


1. Después del GET solo puede ir un solo espacio en blanco
2. La barra invertida (/) indica que se está tratado de accesar el punto de
   entrada por defecto del servidor 80 o 8080 es decir index.htm o index.jsp
   por decir algo
3. En la cadena de parámetros parametros=hola<SPACE>0mundo, se debe usar
    el equialnte a %20 en lugar de espacio en blanco, no se debe dejar espacio en blanco en
    ninguna parte de la cadena pues el parser de http trata de separarlos como
    si fuera otra linea de comando y marca error 505
4. La doble cadena <CR><LF><CR><LF>
   Debe ir , la primera dupla indica que después de los parámetros
   tiene que ir una línea en blanco, propio del protocolo http y la segunda indica al servidor que ejecute el comando.

 De nuevo  . NO DEBEN HABER ESPACIOS EN BLANCO, entre en el comando.

los simbolos <CR><LF> son la representación pictografica de los
comandos que Indican :
             <CR> Control de carro <Enter>       o código 13 de Ascii
             <LF>  Salto de linea     <Line feed> o código 12 de ascii


En algunas ocaciones dependiendo del modem y del servidor hay necesidad de remplazar
<LF> caracter 12 po 10 en la cadena de control

Es importante saber que el espacio en blanco <SPACE> propio de http es %20 , pero el caracter
decimal de espacio en blanco %20 de html es :  %25 %32 %30 ,donde

%= %25
2 = %32
0 = %30

o sea que <SPACE> = %20 son en realidad 3 caracteres represntados cada por respectivo codigo ASCII, que el navegador ve como %20 y lo despliega como un solo caracter en blanco.

Un ejemplo por ejemplo:


Hola%35%3230  :  String para ser enviado desde el modem
Hola%20Mundo  :  Html lo interpreta
Hola Mundo        :  El Texto despelgado por el navegador

Si no se hace asi , el modem regresa un mensaje indicando que no reconoce el 550
indicando que no reconoce el protocolo HTTP/1.1

Si todo es correcto el servidor envia una una cadena con los comandos de
la pagina, tal cual se ve en formato nativo http - web.

Recordemos que el sistema que esta recibiendo no es un navegador y por lo tanto no es capas de interpretar meta-comandos ni tag de la forma.
Dependeno de la versión del modem que se este usando antes de la etiqutas , aparaecen cientos
de caracteres de control que usualmente no son de utilidad y que hay que capturar antes de
tener la informacio util.
<html><body><head> y los devuelve tal cual lo ve en la pagina del servidor.

Por esta razón yo colocó en la pagina que me esta serviendo la información que requiero  solo los comandos del lenguaje script del lado del servidor tales en Php, java que necesito.

No usar javascript pues de nuevo , no tenemos un navegador y el modem GPRS, no entiende ningun lenguaje de script que se ejecute al lado del cliente.
 
Como un tip que uso para saber donde esta la informacion util y desechar el resto suelo
colocar esta entre unos caracteres que yo reconozca a priori por ejemplo

 La cadena de respuesta una vez el moden se cumunique por eejmplo : Bienvenido a mi mundo  la envio así

 <I>Bienvenido a mi mundo<F>

Donde las etiquetaa <I><F> son mias,mias,mias y me sirven como se dijo para saber tonde
retorno el modem la informacion que necesito y evitarme mucho esfuerzo buscando donde
esta dentro de tantos cientos de caracters de control que el servidor envia al que se supone que es un navegador, pero no, es un sencillo programaq texto que no sabe que hacer con todo esto flujo de informacion que le llega, almacenar la informacion que llega desde le modem en buffer circular y buscar la ocurrencia de estos caracteres es ya muy sencillo, digo.

NOTA: El siguiente script de lado del servidor es de mucha utilidad para llevar a
cabo el proceso de depuración , ya que en muchas ocaciones aunque el mensahe esta
llegando al servidor esta mal conformado por cualquier falla de digitacion, por
tener espacios en blanco(mas del 50% de las causa de fallar la comunicacion) .
El script hace un volcado de trafico sobre erl puerto en uestion de la interface de
interes en este caso eth0 y 8080 respectivamente (siendo muy comun el uso del puerto 80
aunque nada recomendable para estos menesteres).

El volcado queda en el archivo /root/salida.txt y puede ser visto con visor tipo less o more o un editor tipo emacs o vi,  de resaltar que el archivo es tipo binario , por lo que al editarlo
el emacs,vi, les, more alertan sobre este hecho, no hay problema solo responder qu continue, y se la cadena de caracteres entrante y la respuesta si la hay , asi el modem no la muestre., como en ocaciones el servidor puede tener otros servicios debemos hacer un proceso de busqueda sobre el archivo sobre caracteres de control, yo por ejemplo busca l ocurrenci de Hola Mundo para
ver si lo trasmitio o no y como lo hizo.




echo "********************************************************"
echo "*                    sniffer iniciado en                                                          *"
echo "*                       /root/salida.txt                                                             *"
echo "*                                                                                                            *"
echo "* Visualilzar con :                                                                                *"
echo "*                   less /root/salida.txt                                                         *"
echo "* Editar o buscar : emacs /root/salida.txt                                            *"
echo "*                                                                                                            *"
echo "********************************************************"

rm -f /root/salida.txt
tcpdump -n -i eth0 -s 0 -w /root/salida.txt src or dst port 8080











Carlos Arturo Castaño G.

Comentarios

Entradas populares