|
Trabajando con sockets TCP |
|
Las clases URL y URLConnector proporcionan mecanismos a muy alto nivel
de acceder a recursos de Internet, basicamente creabamos aplicaciones
clientes que se conectaban a un servidor Web que nos proporcionaba el
recurso requerido.
Ahora vamos a crear nuestros propios servicios y clientes que puedan acceder a esos servicios, es decir, vamos a desarrollar aplicaciones cliente-servidor, para ello necesitamos mecanismos a más bajo nivel de comunicaciones en red. La comunicación tanto a través de TCP como de UDP utiliza la abstracción de sockets para comunicar procesos entre sí. Esta comunicación consiste en la transmisión de un mensaje entre el socket de un proceso (cliente) y el socket de otro proceso (servidor). En esta primera práctica veremos como da soporte Java a Socket TCP. OBLIGATORIO ENTREGAR EL EJERCICIO 3 |
|||
|
En este práctica veremos las clases de Java que nos permite trabajan de forma sencilla con sockets TCP. Antes, vamos a ver una facilidad de Java para manejar direcciones de Internet. Clase InetAddressLa clase java.net.InetAddress nos permite representar en Java direcciones IP. Con ella nos podemos referir a los computadores por sus nombres de host en el DNS (Domain Name Server), y es el propio Java quien realiza la consulta correspondiente para conocer la dirección IP.Típicamente para crear instancias de InetAddress, se invoca el método estático getByName(String) pasándole el nombre DNS del host como parámetro. Este objeto representará la dirección de Internet de ese host, y se podrá utilizar para construir sockets. El siguiente código muestra cómo se puede emplear (código fuente: DireccionIP.java): import java.net.*; public class DireccionIP { public static void main(String[] args) throws Exception { if(args.length != 1) { System.err.println( "Usage: DireccionIP NombreHost"); System.exit(1); } InetAddress a = InetAddress.getByName(args[0]); System.out.println(a); } } Este programa al pasarle un nombre de un host, nos devuelve la dirección IP que tiene asignada, asi: java DireccionIP lm000.it.uc3m.es Obtenemos el siguiente resultado: lm000.it.uc3m.es/163.117.139.214 NOTA:Aunque en el ejemplo, no se han tratado excepciones, este método puede devolver una excepción del tipo UnknownHostException (host desconocido). Modificad el programa para capturar esta excepción. Comunicación cliente/servidor con Socket TCPEl interfaz Java que da soporte a sockets TCP está constituida por las clases ServerSocket y Socket.
Si nos centramos en la parte de comunicaciones, la forma general de implementar un cliente será:
Vamos a ver todo esto con un sencillo ejemplo: una aplicación cliente/servidor de eco, es decir, el servidor repite lo mismo que le envía el cliente, hasta que el cliente quiere finalizar el servicio, para lo cual envía la palabra "Adios" al servidor.
Analizad el siguiente código del cliente EcoCliente.java: import java.net.*; import java.io.*; public class EcoCliente { public static void main(String[] args) throws IOException { Socket socketCliente = null; BufferedReader entrada = null; PrintWriter salida = null; // Creamos un socket en el lado cliente, enlazado con un // servidor que está en la misma máquina que el cliente // y que escucha en el puerto 4444 try { socketCliente = new Socket("localhost", 4444); // Obtenemos el canal de entrada entrada = new BufferedReader(new InputStreamReader(socketCliente.getInputStream())); // Obtenemos el canal de salida salida = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socketCliente.getOutputStream())),true); } catch (IOException e) { System.err.println("No puede establer canales de E/S para la conexión"); System.exit(-1); } BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String linea; // El programa cliente no analiza los mensajes enviados por el // usario, simplemente los reenvía al servidor hasta que este // se despide con "Adios" try { while (true) { // Leo la entrada del usuario linea = stdIn.readLine(); // La envia al servidor salida.println(linea); // Envía a la salida estándar la respuesta del servidor linea = entrada.readLine(); System.out.println("Respuesta servidor: " + linea); // Si es "Adios" es que finaliza la comunicación if (linea.equals("Adios")) break; } } catch (IOException e) { System.out.println("IOException: " + e.getMessage()); } // Libera recursos salida.close(); entrada.close(); stdIn.close(); socketCliente.close(); } } Analizad el siguiente código del servidor EcoServidor.java: import java.io.*; import java.net.*; public class EcoServidor { public static final int PORT = 4444; public static void main(String[] args) throws IOException { // Establece el puerto en el que escucha peticiones ServerSocket socketServidor = null; try { socketServidor = new ServerSocket(PORT); } catch (IOException e) { System.out.println("No puede escuchar en el puerto: " + PORT); System.exit(-1); } Socket socketCliente = null; BufferedReader entrada = null; PrintWriter salida = null; System.out.println("Escuchando: " + socketServidor); try { // Se bloquea hasta que recibe alguna petición de un cliente // abriendo un socket para el cliente socketCliente = socketServidor.accept(); System.out.println("Connexión acceptada: "+ socketCliente); // Establece canal de entrada entrada = new BufferedReader(new InputStreamReader(socketCliente.getInputStream())); // Establece canal de salida salida = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socketCliente.getOutputStream())),true); // Hace eco de lo que le proporciona el cliente, hasta que recibe "Adios" while (true) { String str = entrada.readLine(); System.out.println("Cliente: " + str); salida.println(str); if (str.equals("Adios")) break; } } catch (IOException e) { System.out.println("IOException: " + e.getMessage()); } salida.close(); entrada.close(); socketCliente.close(); socketServidor.close(); } } Para probar como funciona este sencillo programa, debereis arrancar primero el servidor, que se quedará a la escucha de peticiones, y despues el cliente. Si lo haceis en orden inverso, al arrancar el cliente se producirá una IOException. CONSEJO: Probad que ocurre cuando se producen errores: se muere el programa cliente, se muere el programa servidor...y modificad los programas si lo considerais oportuno. Ahora tendreis que hacer algunas modificaciones en los programas anteriores:
|
|||
|
NOTA: Considerad el caso más sencillo: los ficheros que se transmiten son
de texto. Para indicar la finalización de una transferencia utilizad "\0".
Para transmitir un error del servidor al cliente, utilizad un código que no se
correspondan a un caracter alfanumérico, por ejemplo, ESC(0x1B).
get "nombre_completo_fichero" bye lock "nombre_fichero" |
|||
|
|