Bienvenidos sean a este post, hoy veremos un ejemplo de como implementar un ejemplo de cliente/servidor simple para entender el concepto, primero crearemos un cliente para conectarnos a un servidor y testear nuestra conexion y en el segundo caso crearemos un servidor local y modificaremos el cliente para poder probarlo, comencemos con nuestro cliente y para ello vamos a crear una nueva aplicacion:

  • Application Name: Cliente ECHO
  • Domain Company: example.org
  • API SDK Minimum: 14
  • Add an Activity: Empty Activity
  • Activity Name: MainActivity
  • Layout Name: activity_main

Nuestro primer paso sera agregar el id a nuestro elemento TextView en el layout, para ello debemos ir a activity_main.xml y en TextView agregar la siguiente linea:

android:id="@+id/Texto01"

Este sera el id para nuestro codigo Java, el TextView quedara de la siguiente forma:

    <TextView
        android:id="@+id/Texto01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

Con esta sola modificacion, el resto debe quedar como se genero podemos pasar a modificar nuestra clase MainActivity, para ello reemplacemos el codigo generado automaticamente por este:

package org.example.clienteecho;

import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class MainActivity extends AppCompatActivity {
    private TextView pantalla;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pantalla = (TextView) findViewById(R.id.Texto01);
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .permitNetwork().build());
        ejecutaCliente();
    }

    private void ejecutaCliente(){
        String ip = "172.217.162.4";
        int puerto = 7;
        log(" socket " + ip + " " + puerto);
        try{
            Socket sk = new Socket(ip,puerto);
            BufferedReader entrada = new BufferedReader(new
                    InputStreamReader(sk.getInputStream()));
            PrintWriter salida = new PrintWriter(
                    new OutputStreamWriter(sk.getOutputStream()),true);
            log("enviando ... Hola Mundo!");
            salida.println("Hola mundo");
            log("recibiendo ... " + entrada.readLine());
            sk.close();
        }
        catch (Exception e){
            log("error: " + e.toString());
        }
    }

    private void log(String cadena){
        pantalla.append(cadena + "\n");
    }
}

Primero crearemos un objeto que sera el link entre el elemento del layout y nuestro codigo, luego tendremos el metodo onCreate() en el cual asignaremos a nuestro objeto el elemento que identificamos antes por medio de findViewById(), despues viene un metodo llamado StrictMode la cual es una herramienta para desarrolladores que detecta errores que podrias estar cometiendo y te lo informa, una de las verificaciones mas interesantes es que chequee que no se este ejecutando un acceso a la red por medio del hilo principal pero en este caso no le daremos tanta importancia sino nos centraremos en ver el correcto funcionamiento de la misma, despues llamara al metodo ejecutaCliente().

El metodo ejecutaCliente() tendra dos variables: una llamada ip y otra llamada puerto, la primera de tipo String almacenara la direccion IP del servidor y luego el puerto del mismo, despues llamara al metodo log() (todavia no existe pero ya lo crearemos) donde mostrara los datos antes establecidos, luego tendremos un bloque try/catch donde primero crearemos un objeto de tipo Socket llamado sk, en el cual utilizaremos los datos antes ingresados, luego crearemos un objeto llamado entrada la cual sera de tipo BufferedReader la cual sera la encargada de leer la informacion ingresada en el socket, el siguiente objeto llamado salida sera el encargado escribir en el socket, todo por medio de PrintWriter, nuestro siguiente linea mostrara un mensaje por medio de log(), la proxima linea enviara los datos al socket por medio de salida y println(), luego por medio de log mostraremos el mensaje almacenado en nuestro socket gracias a entrada y readline(), y finalmente cerramos nuestro socket, en el catch mostraremos un mensaje de error en caso de que ocurra alguno.

Por ultimo el metodo log(), solamente sera el encargado de agregar el texto que le enviemos a nuestro elemento llamado pantalla, con todo esto realizado debemos hacer la ultima modificacion para poder probarlo, para ello debemos ir a AndroidManifest.xml donde agregaremos la siguiente linea:

<uses-permission android:name="android.permission.INTERNET" />

Con esta modificacion realizada podemos probar nuestra aplicacion, si lo compilamos y enviamos a un dispositivo o equipo virtual esta es una salida que podemos obtener

Este mensaje se debio a que el servidor no esta encendido o no tiene habilitado el puerto 7 para utilizar el echo, en cambio si tuvieramos un servidor funcionando correctamente la pantalla habria sido asi

En este caso tuve que implementar una solucion para este inconveniente pero hablare de esta solucion al final, como pueden observar funciono correctamente la informacion que enviamos a salida por medio de println() fue recuperada por entrada y el metodo readline(), para nuestro siguiente prueba crearemos un programa que usaremos de servidor, para ello crearemos una nueva aplicacion pero solamente de Java con Android Studio con las siguientes caracteristicas:

  • Application Name: Servidor ECHO
  • Domain Company: example.org
  • API SDK Minimum: 14
  • Add an Activity: Add No Activity

Una vez creado nuestra nueva aplicacion debemos ir a File->New->New Module, seleccionen Java Library, luego en Library Name pongan servidor, en Java package name, pulsen Edit y modifiquen el campo a org.example.servidorecho y pulsen Done, por ultimo en Java class name ingresen ServidorECHO, con todas estas modificaciones pulsen Finish para generar el nuevo modulo, nuestro siguiente paso sera ir a apps y seleccionar Edit Configurations como se ve en la siguiente imagen

Luego de esto aparecera una nueva ventana, deben seleccionar el boton mas (+) en el esquina izquierda superior, aparecera un nuevo menu y seleccionen application como se ve en la siguiente imagen

En el nuevo cuadro que aparezca debemos modificar los siguientes campos:

  • Name: servidor
  • Main Class: org.example.servidor.ServidorECHO
  • Use Classpath of module: servidor

El cuadro debera quedar de esta forma

Una vez hecha todas las modificaciones, pulsen Ok para que tomen efectos las mismas, nuestro siguiente paso sera modificar el codigo generado automaticamente de la clase ServidorECHO por el siguiente:

package org.example.servidorecho;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class ServidorECHO {
    public static void main(String[] args){
        try{
            System.out.println("Servidor en marcha...");
            ServerSocket sk = new ServerSocket(7);
            while(true){
                Socket cliente = sk.accept();
                BufferedReader entrada = new BufferedReader(
                        new InputStreamReader(cliente.getInputStream()));
                PrintWriter salida = new PrintWriter(new OutputStreamWriter(
                        cliente.getOutputStream()),true);
                String datos = entrada.readLine();
                salida.println(datos);
                cliente.close();
                System.out.println(datos);
            }
        }
        catch(Exception e){
            System.out.println(e);
        }
    }
}

En este ejemplo usaremos al formato de Java, es decir tendremos un metodo main() el cual es el verdadero corazon de nuestro ejemplo, en este sector estan todos mis posts sobre Java, luego tendremos el bloque try/catch ante cualquier eventualidad, en el try primero mostraremos un mensaje, luego crearemos un objeto de tipo SocketServer llamado sk y le informaremos el numero de puerto que abriremos, esto nos permitira que nuestra computadora abra este puerto y podamos conectarnos, en el siguiente paso tendremos un bucle while, en este crearemos un objeto llamado cliente del tipo Socket y le asignaremos que el objeto creado anteriormente (sk) acepte conexiones por medio de accept(), despues crearemos dos objetos al igual que en el ejemplo anterior las cuales se encargaran de leer y escribir en el socket creado, luego habra un objeto llamado datos que se encargara de leer los datos recibidos en entrada, luego escribira en salida los datos obtenidos en entrada, para luego cerrar nuestro socket y finalmente mostrar la informacion de datos en pantalla por medio de println(), luego en el catch mostraremos cualquier error que se nos produzca, si lo ejecutamos el programa quedara escuchando en el Android Studio, nuestra siguiente modificacion deberemos hacerla en la aplicacion Cliente ECHO.

En nuestra aplicacion debemos modificar la direccion a donde debemos conectarnos, como el emulador es considerado otro equipo no pueden utilizar la ip 127.0.0.1 sino que deben abrir una terminal en Linux o una ventana de DOS en Windows, en Linux pueden usar el comando ip addr y nos devolvera la direccion ip de nuestro equipo, en el caso de windows usen ipconfig, en cualquiera de los casos copien la direccion ip que les informe y lo utilizan en la siguiente linea:

String ip = "172.128.41.13"

Esta es la direccion ip de mi equipo en la de ustedes puede ser distinta, con esta modificacion realizada si compilamos y lo probamos de nuevo deberemos obtener una salida de este estilo

En este caso funciono perfectamente, en el lado del “servidor” deberan tener unas notificaciones de este estilo

Con esto ya aplicamos los dos ejemplos pero como les dije antes para hacer funcionar el cliente ECHO sin este servidor tuve que implementar una solucion. El inconveniente fue que no pude encontrar un servidor en internet que tenga el puerto 7 abierto asi que segui los pasos de este tutorial sobre Debian y lo instale en un equipo virtual, una vez instalado con todos los pasos y habilitado sobre mi red, instale el xinetd

$ sudo apt-get install xinetd

Luego habilite el servicio de echo, para ello debemos modificar el servicio en el archivo /etc/xinetd.d/echo, donde dice disable cambien el yes por no, reinicien el servicio de xinetd por medio del siguiente comando:

$ sudo service xinetd restart

Con estos simples pasos podran crear un servidor sobre la red y podran probarlo, obteniendo la primera imagen exitosa.

Nota: Esta no es la unica instalacion de Linux que explico, se las recomiendo para hacer pruebas y/o instalar lenguajes para practicar como por ejemplo Java, en un futuro no muy lejano explicare sobre Linux, como usarlo, como lenguaje de programacion y todas las maravillosas disponibles.

En resumen, hoy hemos visto como implementar un socket, primero creando un programa cliente, luego creando un simple programa de servidor, como pudimos implementarlo uno al otro, como obtener una salida, como poder solucionarlo, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios