- Un servidor por sockets para las puntuaciones

 

Siguiendo la estructura básica de un cliente y un servidor TCP que acabamos de ver, va a resultar muy sencillo implementar un protocolo que permita a varios clientes conectarse a un servidor para consultar la lista de puntuaciones o mandar nuevas puntuaciones.El primer lugar, tenemos que diseñar un protocolo que permita realizar las dos operaciones.

Para consultar puntuaciones el cliente se conectará al servidor y le mandará los caracteres PUNTUACIONES (solo se permite en mayúsculas) seguido de un salto de línea. El servidor mandará todo el listado de puntuaciones, separadas por caracteres de salto de línea. A continuación, se cerrará la conexión.

Cliente:                     PUNTUACIONES

Servidor:                   19000 Pedro Perez

17500 María Suarez

13000 Juan García

 Para almacenar una nueva puntuación el cliente se conectará al servidor y mandará un texto con la puntuación obtenida, seguido de un salto de línea. El servidor lo reconocerá como una nueva puntuación siempre que este texto no sea PUNTUACIONES. En tal caso almacenará la puntuación y mandará los caracteres OK seguidos de un salto de línea. A continuación se cerrará la conexión.

Cliente:        32000 Eva Gutierrez

Servidor:       OK

En segundo lugar, hay que elegir un número de puerto para realizar la comunicación; por ejemplo el 1234.

Ejercicio paso a paso: Estudio del protocolo PUNTUACIONES utilizando el comando telnet.

El siguiente ejercicio nos muestra un truco para testear si un servidor que utiliza TCP funciona correctamente. Te recomendamos que lo utilices antes de realizar la programación del cliente. Por una parte, te permitirá asegurarte que tanto la conexión, como el servidor funcionan correctamente. Por otra parte, te asegurarás que has entendido correctamente el protocolo a implementar.

NOTA: Para que el ejemplo funcione en la dirección IP 158.42.146.127 ha de haber un servidor de PUNTUACIONES en funcionamiento. En caso de no ser así, implementar tu propio servidor de PUNTUACIONES,  tal y como se muestra en uno de los siguientes ejercicios.

1.     Para conectarse al servidor desde un intérprete de comandos (símbolo del sistema/shell) escribe:

  telnet 158.42.146.127 1234

2.     Si se establece la conexión, escribe un número seguido de tu nombre y pulsa <Intro>. Por ejemplo:

 14000 Juan García

3.     La respuesta obtenida ha de ser OK y luego se cerrará la conexión.

4.     Repite el punto 2 y tras la conexión escribe:

  PUNTUACIONES

5.     La respuesta obtenida ha de ser la lista de puntuaciones donde ha de estar la que acabas de introducir.

Ejercicio paso a paso: Almacenando las puntuaciones mediante un protocolo basado en sockets

1.     Crea un nuevo proyecto Java  (Java SE, no para Android) y llámalo ServidorPuntuacionesSocket. Este proyecto ha de contener la clase ServidorPuntuaciones. Instrucciones detalladas se muestran en el ejercicio Un servidor de ECHO.

2.     Reemplaza en código por el que se muestra a continuación:

public class ServidorPuntuaciones {

    public static void main(String args[]) {
      Vector<String> puntuaciones = new Vector<String>();

      try {
         ServerSocket s = new ServerSocket(1234);
         System.out.println("Esperando conexiones...");

         while (true) {
            Socket cliente = s.accept();
            BufferedReader entrada = new BufferedReader(
                  new InputStreamReader(cliente.getInputStream()));
            PrintWriter salida = new PrintWriter(new OutputStreamWriter(
                  cliente.getOutputStream()), true);
            String datos = entrada.readLine();
            if (datos.equals("PUNTUACIONES")) {
               for (int n = 0; n < puntuaciones.size(); n++) {
                  salida.println(puntuaciones.get(n));
               }
            } else {
               puntuaciones.add(0, datos);
               salida.println("OK");
            }
            cliente.close();
         }
      } catch (IOException e) {
         System.out.println(e);
      }
   }
}

 

3.     Ejecuta el proyecto

4.     Verifica que en la vista Run aparece: "Esperando conexiones..."

5.     Desde la vista Run podrás detener la aplicación pulsando en el cuadro rojo.

NOTA:Si ejecutas de nuevo la aplicación sin pararla primero, dará un error. Esto es debido a que la aplicación ya lanzada no es detenida y esta aplicación tiene asociado el puerto 1234. El sistema no permitirá que una nueva aplicación escuche este puerto.

 

6.     Abre el proyecto Asteroides y crea la siguiente clase:

public class AlmacenPuntuacionesSocket implements AlmacenPuntuaciones{

  public AlmacenPuntuacionesSocket() {
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.
            Builder().permitNetwork().build());
  }

  public void guardarPuntuacion(int puntos, String nombre, long fecha){
   try {
      Socket sk = new Socket("X.X.X.X", 1234);
      BufferedReader entrada = new BufferedReader(
                new InputStreamReader(sk.getInputStream()));
      PrintWriter salida = new PrintWriter(
                new OutputStreamWriter(sk.getOutputStream()),true);
      salida.println(puntos + " " + nombre);
      String respuesta = entrada.readLine();
      if (!respuesta.equals("OK")) {
         Log.e("Asteroides", "Error: respuesta de servidor incorrecta");
      }
      sk.close();
   } catch (Exception e) {
      Log.e("Asteroides", e.toString(), e);
   }
  }

  public Vector<String> listaPuntuaciones(int cantidad) {
   Vector<String> result = new Vector<String>();
   try {
      Socket sk = new Socket("X.X.X.X", 1234);
      BufferedReader entrada =    new BufferedReader(
             new InputStreamReader(sk.getInputStream()));
      PrintWriter salida = new PrintWriter(
                new OutputStreamWriter(sk.getOutputStream()),true);
      salida.println("PUNTUACIONES");
      int n = 0;
      String respuesta;
      do {
         respuesta = entrada.readLine();
         if (respuesta != null) {
            result.add(respuesta);
            n++;
         }
      } while (n < cantidad && respuesta != null);
      sk.close();
   } catch (Exception e) {
      Log.e("Asteroides", e.toString(), e);
   }
   return result;
  }
}

7.     Sustituiye las dos apariciones de "X.X.X.X" por la dirección IP donde esté ejecutándose el servidor. 

NOTA: El comando ipconfig (Windows) o ifconfig (Linux/Mac)te permite averiguar la dirección IP de tu ordenador. No utilices como IP 127.0.0.1 (localhost) dado que, aunque se ejecuten en la misma máquina, la IP del emulador es diferente a la del PC.

8.     Recuerda que ahora la aplicación Asteroides necesita el permiso INTERNET. Y tiene que ser compilada con una versión mínima 9 (para StrictMode).

9.  Ejecuta la aplicación y accede a visualizar la lista de puntuaciones. Luego inicia una partida nueva.

10.  Verifica que en la vista Consola aparecen las consultas al servidor.

11.  Para terminar, reemplaza la IP por la siguiente "158.42.146.127" para conectarte a un servidor compartido. 

NOTA: Es posible que este servicio no haya sido iniciado.

12.  Modifica el código correspondiente para que la nueva clase pueda ser seleccionada como almacén de las puntuaciones.    

 

13.  Comprueba si otros usuarios han accedido a este servidor y aparecen sus puntuaciones.

Preguntas de repaso: El interfaz socket