Leer y Escribir a través de un Socket

El siguiente programa es un ejemplo sencillo de cómo establecer una conexión entre un programa cliente y otro servidor utilizando sockets. La clase Socket del paquete java.net es una implementación independiente de la plataforma de un cliente para un enlace de comunicación de dos vías entre un cliente y un servidor. La clase Socket se sitúa en la parte superior de una implementación dependiente de la plataforma, ocultando los detalles de los sistemas particulares a un programa Java. Utilizando la clase java.net.Socket en lugar de tratar con código nativo, los programas Java pueden comunicarse a través de la red de una forma independiente de la plataforma.

Este programa cliente, EchoTest, conecta con el Echo del servidor (en el port 7) mediante un socket. El cliente lee y escribe a través del socket. EchoTest envía todo el texto tecleado en su entrada estandard al Echo del servidor, escribiendole el texto al socket. El servidor repite todos los caracteres recibidos en su entrada desde el cliente de vuelta a través del socket al cliente. El programa cliente lee y muestra los datos pasados de vuelta desde el servidor.

import java.io.*;
import java.net.*;

public class EchoTest {
    public static void main(String[] args) {
        Socket echoSocket = null;
        DataOutputStream os = null;
        DataInputStream is = null;
        DataInputStream stdIn = new DataInputStream(System.in);

        try {
            echoSocket = new Socket("taranis", 7);
            os = new DataOutputStream(echoSocket.getOutputStream());
            is = new DataInputStream(echoSocket.getInputStream());
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: taranis");
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to: taranis");
        }

        if (echoSocket != null && os != null && is != null) {
            try {
                String userInput;

                while ((userInput = stdIn.readLine()) != null) {
                    os.writeBytes(userInput);
                    os.writeByte('\n');
                    System.out.println("echo: " + is.readLine());
                }
                os.close();
                is.close();
                echoSocket.close();
            } catch (IOException e) {
                System.err.println("I/O failed on the connection to: taranis");
            }
        }
    }
}
Paseemos a través del programa e investiguemos las cosas interesantes.

Las siguientes tres líneas de código dentro del primer bloque try del método main() son críticos -- establecen la conexión del socket entre el cliente y el servidor y abre un canal de entrada y un canal de salida sobre el socket:

echoSocket = new Socket("taranis", 7);
os = new DataOutputStream(echoSocket.getOutputStream());
is = new DataInputStream(echoSocket.getInputStream());
La primera línea de esta secuencia crea un nuevo objeto Socket y lo llama echoSocket. El constructor Socket utilizado aquí (hay otros tres) requiere el nombre de la máquina y el número de puerto al que quiere conectarse. El programa de ejemplo utiliza el host taranis, que es el nombre de una máquina (hipotética) de nuestra red local. Cuando teclees y ejecutes este programa en tu máquina, deberías cambiar este nombre por una máquina de tu red. Asegurate de que el nombre que utiliza tienes el nombre IP totalmente cualificado de la máquina a la que te quieres conectar. El segundo argumento es el número de puerto. El puerto número 7 es el puerto por el que escucha el Echo del servidor.

La segunda línea del código anterior abre un canal de etnrada sobre el socket, y la tercera línea abre un canal de salida sobre el mismo socket. EchoTest sólo necesita escribir en el stream de salida y leer del stream de entrada para comunicarse a través del socket con el servidor. El resto del programa hace esto. Si no estás familiarizado con los streams de entrada y salida, podrías querer leer Streams de Entrada y Salida.

La siguiente sección de código lee desde el stream de entranda estandard de EchoTest (donde el usuario teclea los datos) una línea cada vez. EchoTest escribe inmediatamente la entada seguida por un carácter de nueva línea en el stream de salida conectado al socket.

String userInput;

while ((userInput = stdIn.readLine()) != null) {
    os.writeBytes(userInput);
    os.writeByte('\n');
    System.out.println("echo: " + is.readLine());
}
La última línea del bucle while lee una línea de información desde el stream de entrada conectado al socket. El método readLine() se bloquea hasta que el servidor haya devuelto la información a EchoTest. Cuando readline() retorna, EchoTest imprime la información en la salida estandard.

Este bloque continua -- EchoTest lee la entrada del usuairo, la envía al servidor Echo, obtiene una respuesta desde el servidor y la muestra -- hasta que el usuario teclee un carácter de final de entrada.

Cuando el usuario teclea un carácter de fin de entrada, el bucle while termina y el programa continúa ejecutando las siguientes líneas de código:

os.close();
is.close();
echoSocket.close();
Estas línea de código caen en la categoría de limpieza del hogar. Un programa con buen comportamienteo, se limpia a sí mismo y este programa tiene buen comportamiento. Estas tres líneas de código cierran las streams de entrada y salida conectados al socket, y cierra la conexión del socket con el servidor. El orden es importante -- debe cerrar los streams conectados a un socket antes de cerrar éste.

Este programa cliente tiene un comportamiento correcto y sencillo porque el servidor Echo implementa un protocolo sencillo. El cliente envía texto al servidor, y el servidor lo devuelve. Cuando tus programas clientes hablen con servidores más complicados como un servidor http, tu programa cliente también será más complicado. Si embargo, las cosas básicas son las que has visto en este programa:

  1. Abrir un socket.
  2. Abrir un stream de entrada y otro de salida hacia el socket.
  3. Leer y escribir a través del socket de acuerdo al protocolo del servidor.
  4. Cerrar los Streams.
  5. Cerrar el socket.

Sólo el paso 3 será diferente de un cliente a otro, dependiendo del servidor.Los otros pasos permanecen inalterables.

También puede ver

java.net.Socket


Ozito