Práctica 3: Introducción a los sockets en Java

Documentos relacionados
Sockets. Los sockets son un mecanismo de comunicación entre procesos que se utiliza en Internet.

Arquitecturas cliente/servidor

Federico Peinado

Capítulo 5. Programación de aplicaciones de red

1. Cuántas sentencias hay en la secuencia principal del siguiente programa?

Unidad II. Fundamentos de programación en Java. Ing. José Luis Llamas Cárdenas

1.- FUNDAMENTOS FUNCIONAMIENTO GENÉRICO JAVA SOCKETS Creación de Streams de Entrada...7

Instrucciones de configuración del acceso remoto (VPN) de la UCLM para Windows, Mac y Linux

Flujos (streams) Programación. Licenciatura Lingüística y Nuevas Tecnologias Nadjet Bouayad-Agha

UNIVERSIDAD CARLOS III DE MADRID DEPARTAMENTO DE INGENIERÍA TELEMÁTICA. Daniel Díaz Sánchez

Práctica III: Streams, Readers y Writers

Guía - Taller # 2 (JAVA)

1 SOCKETS EN JAVA. Sistemas Distribuidos::Sockets en Java EUI-SG/INFOR.UVA.ES 1

UNIVERSIDADE DA CORUÑA Departamento de Tecnoloxías da Información e as Comunicacións LABORATORIO DE RC: TUTORIAL DE SOCKETS EN JAVA

Examen de Redes - ETSIA 9 de septiembre - Primer Parcial

EJEMPLOS PROGRAMACIÓN SOCKET - JAVA

Sockets en Java. Prof. Wílmer Pereira Universidad Simón Bolívar

Sockets. Sockets. 1 Introducción

PROGRAMACIÓN CLIENTE-SERVIDOR MEDIANTE SOCKETS EN JAVA

Tema: Introducción al IDE de Microsoft Visual C#.

UNIVERSIDAD POLITÉCNICA DE PACHUCA SOCKETS EN JAVA

TEMA 7: Ficheros. TEMA 7: Ficheros Concepto de fichero

Tema 4. Excepciones en Java

CLASE SOCKET. 1. Crear un nuevo socket usando un constructor de la clase. 2. El socket trata de conectarse al host remoto.

Práctica 5: Servidor web concurrente en Java

LA ESTRUCTURA DE DATOS PILA EN JAVA. CLASE STACK DEL API JAVA. EJEMPLO Y EJERCICIOS RESUELTOS. (CU00923C)

Examen Final de Redes - ETSIA - 24 de junio de 2006

Comandos TCP-IP para Windows

Java desde Consola Utilizando Java sin Path

Lab 01: Programación de Sockets en TCP

Ficheros y streams. Desde el punto de vista de Java, cada fichero no es más que una secuencia o flujo de bytes [stream].

Desarrollo de Aplicativos con winsockets

Sockets en Java. La Creatividad proviene de un conflicto de ideas. Uso de Sockets

Carlos Montenegro. Programación Orientada a Objetos Proyecto Curricular de Ingeniería de Sistemas

FACULTAD DE INGENIERÍA

configuración de tu equipo. Rellena la siguiente tabla y contesta a las siguientes preguntas:

Aspectos Básicos de Networking

Las clases Java Socket y ServerSocket

QUE SON Y PARA QUE SIRVEN LAS DIRECCIONES IP, LA MASCARA DE SUBRED, LA PUERTA DE ENLACE Y LAS DNS.

Objetivos de la sesión. Aplicación de consola 7/30/11. Código con que se inicia un programa en Visual C# (aplicación de consola)

Direcciones IP y puertos

Test : Conteste exclusivamente en una HOJA DE LECTURA ÓPTICA, no olvidando marcar que su tipo de examen es A.

Universidad de Cantabria

Redes de Ordenadores

Manual de Instrucciones para el uso con un ordenador

Unidad Didáctica 2. Elementos básicos del lenguaje Java Tipos, declaraciones, expresiones y asignaciones

Desde los programas más simples escritos en un lenguaje de programación suelen realizar tres tareas en forma secuencial.

Equipamiento ADSL» Inalámbrico. Adaptador USB PAUTAS PARA LA VERIFICACION TCP/IP

Introducción a Windows 98

Aplicación para el Registro de Piscinas de Salud Pública del Servicio Canario de la Salud. Manual de Usuario 1.7

Programación Orientada a Objetos. Java: Excepciones

Programación para redes con Java

Soluciones inalámbricas. Guía rápida para configurar un enlace con equipos ENS500 en modo WDS Bridge

Clases Java para comunicaciones en red

Programación Orientada a Objetos. Tema 7: Persistencia

5. Sentencias selectivas o condicionales

Java: comunicación en Internet. Modem. Satelite UMTS W-LAN. Láser. Fibra óptica. Conceptos básicos

Práctica 5MODBUS: Bus Modbus

Información de la lectura en un programa.

ESCUELA POLITÉCNICA SUPERIOR PRÁCTICA 2: EXPRESIONES, PRINTF Y SCANF

4.2 Servicio de exploración de E/S

Práctica 2: Java Remote Method Invocation (RMI)

FUNCIONES PHP: DECLARACIÓN Y LLAMADAS. PARÁMETROS, RETURN. EJERCICIOS EJEMPLOS RESUELTOS. (CU00827B)

Tema 7.- Fundamentos de la Programación Orientada a Objetos

COMO CREAR UNA RED LOCAL ENTRE EQUIPOS CON WINDOWS

COMUNICACIÓN ENTRE EL CLIENTE Y SERVIDOR SIN PHP Y CON PHP. INTÉRPRETE PHP Y GESTOR DE BASES DE DATOS (CU00804B)

TARJETAS: POS INTEGRADO

Sistemas Operativos: Programación de Sistemas. Curso Oscar Déniz Suárez Alexis Quesada Arencibia Francisco J.

INSTITUTO ELECTORAL DEL ESTADO DE MÉXICO SECRETARÍA EJECUTIVA UNIDAD DE INFORMÁTICA Y ESTADÍSTICA

Práctica 5: Implementación en C++ de sistemas cliente/servidor basados en comunicación

Introducción. Word Autor: Viviana M. Lloret Prof. de Matemática e Informática Blog: aulamatic.blogspot.com

Práctica 4: Java Remote Method Invocation (RMI)

Introduciendo datos desde el

Crear documentos de texto en Google Docs. Avanzado

Arrays unidimensionales. Dim.Option Base. Erase. Ejemplos en Visual Basic (CU00311A)

Entrada y Salida con Java

Redes de Computadores - Problemas y cuestiones

Funciones básicas del depurador

QUÉ ES UNA CLASE JAVA? ATRIBUTOS (PROPIEDADES O CAMPOS), CONSTRUCTOR Y MÉTODOS. (CU00623B)

COMO CAMBIAR CONTRASEÑA A MIS

Tipos DataInputStream/DataOutputStream: L/E de datos de tipo simple y Cadenas (Strings) ObjectInputStream/ObjectOutputStream: para persistencia de obj

ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA UNIVERSIDAD DE SEVILLA COMPUTADORAS Y COMUNICACIONES. Redes informáticas de área local (LAN)

Práctica 4: Herencia. Objetivos:

TEMA 1. Introducción a la programación. CONSIDERACIONES GENERALES.

INTRODUCCION A LA PROGRAMACION EN JAVA

HERRAMIENTAS BASICAS DE MANEJO DE WINDOWS

Shell Script de instalación y configuración para el servicio DHCP en CentOS v5.x. Manual de instrucciones.

Programación Orientada a Objetos. Java: Excepciones

En la parte inferior de la pantalla se podrá ver el estado de la última copia y la fecha y hora actual.

FACULTAD DE INGENIERÍA

Guía de Inicio Rápido

INTERFACE COMPARATOR. DIFERENCIAS ENTRE COMPARATOR Y COMPARABLE. CLASE COLLECTIONS. EJERCICIOS RESUELTOS. (CU00918C)

Manual de usuario de cga-comparte-impresora-v4

Manual de instalación AUTOFIRMA LA SEDE ELECTRÓNICA XUNTA DE GALICIA GUÍAS DE AYUDA DE

IIC1103 Introducción a la Programación. Ayudantía: Archivos

Tutorial para saber cómo crear una cuenta de correo electrónico

Manual del padre de familia

Conceptos a tratar. Fundamentos de la Programación Orientada a Objetos Ampliación sobre clases y objetos

Transcripción:

Práctica 3: Introducción a los sockets en Java En esta práctica se va a tener una primera toma de contacto con la interfaz de los sockets en Java. Para ello plantearemos una serie de ejercicios muy sencillos que ilustran algunos conceptos básicos del funcionamiento de los sockets TCP en Java. 1. Entorno de trabajo Java está disponible para diferentes sistemas operativos y con diversos entornos de programación. Nosotros vamos a trabajar en Linux. Para editar el programa os sugerimos el uso del editor kwrite. Por otra parte, recuerda que si el nombre del fichero fuente de nuestro programa es Ejemplo.java lo compilaremos mediante la orden javac Ejemplo.java, y lo ejecutaremos tecleando java Ejemplo. Además, el lenguaje Java distingue entre mayúsculas y minúsculas, y el nombre del fichero debe coincidir con el de la clase principal. Toda la información sobre las clases de Java puede encontrarse en la página Web de Sun: http://java.sun.com/j2se/1.4/docs/api. Por otra parte, en http://www.ulpgc.es/otros/tutoriales/java se puede consultar un curso de Java.

P3-2 Prácticas de Redes de Computadores 2. Cómo establecer conexión con un servidor La clase java.net.socket es la clase Java fundamental para realizar operaciones TCP desde el extremo cliente. A partir de aquí nos referiremos a ella como clase Socket. Esta clase posee varios constructores que permiten especificar el host destino y el número de puerto al que queremos conectarnos. El host puede especificarse como un objeto InetAddress (que corresponde a una dirección IP) o como un String. El número de puerto siempre se indica como un valor int que puede variar desde el 1 al 65.535. Empezaremos probando el costructor más sencillo: public Socket (String host, int puerto) throws IOException, UnknownHostException Este constructor crea un socket TCP e intenta conectarlo al host y puerto remotos especificados como parámetros. Si el servidor DNS no está en funcionamiento o no puede resolver el nombre, el constructor lanzará una excepción UnknownHostException. Si el nombre se resuelve pero el socket no puede conectar por alguna otra razón, se lanzará una excepción IOException. Esto puede deberse, entre otras razones, a que el puerto destino en el servidor no esté abierto, existan problemas de encaminamiento en la red para alcanzar el destino o simplemente el servidor especificado esté apagado. Ejercicio 1: Escribe un programa en java, ClienteTCP1.java, que sea capaz de aceptar dos parámetros de entrada en línea de órdenes para establecer una conexión: el nombre de un servidor y un número de puerto al que conectar en ese servidor. El programa debe visualizar un mensaje por pantalla indicando si la conexión se ha establecido o no. En caso de éxito debe mostrar también el número de puerto y el nombre del servidor con el que ha conectado, y en caso de fallo indicar el motivo: Nombre de servidor desconocido o No es posible realizar conexión, dependiendo el tipo de excepción ocurrida (ver notas en página siguiente). Prueba tu programa con los siguientes servidores y puertos, comprobando lo que sucede: 1. mail.redes.upv.es 25 2. herodes.redes.upv.es 25 3. zoltar.redes.upv.es 25

Introducción a los sockets en Java P3-3 Ejercicio 1 (NOTAS): Para facilitar la depuración, el programa debe comprobar si hay parámetros de entrada y, si no se han suministrado, intentar conectarse al puerto 25 del servidor zoltar.redes.upv.es. Por otra parte, recuerda que los parámetros de entrada en Java son de tipo String y dado que el puerto en el constructor Socket es un int, es necesario realizar una conversión de tipo. De este modo, si args[1] es el parámetro correspondiente al puerto, la conversión puede hacerse, por ejemplo, como: int puerto = Integer.parseInt(args[1]). Otra opción para crear el socket es pasarle como parámetro la dirección IP mediante un objeto InetAddress, en lugar del nombre de dominio del servidor. En este caso se podría generar una excepción IOException si no se puede conectar pero no una UnknownHostException. Ahora la consulta al DNS se lleva a cabo al crear el objeto InetAddress y es, en este momento, cuando pueden surgir los problemas relacionados con la traducción nombre-dirección IP. La clase Inet- Address posee varios métodos estáticos que permiten crear objetos Inet- Address inicializados de forma adecuada. El más popular es: public static InetAddress InetAddress.getByName(String HostName) que se utiliza de la forma: InetAddress dirip = InetAddress.getByName( www.upv.es ) Si se van a abrir varias conexiones al mismo host (como haremos en el último apartado de la práctica) es más eficiente emplear este constructor, para resolver únicamente una vez la dirección IP a la que se desea conectar e indicarla directamente en el constructor Socket. Ejercicio 2: Copia el ClienteTCP1.java a ClienteTCP2.java. Modifícalo para que traduzca el nombre del host antes de crear el socket. Comprueba que funciona de forma equivalente. 3. Cómo obtener información sobre la conexión establecida La clase Socket dispone de varios métodos que permiten obtener información sobre la conexión establecida entre el cliente y el servidor.

P3-4 Prácticas de Redes de Computadores Entre ellos podemos citar getlocaladdress() y getinetaddress(), que devuelven las direcciones IP local y remota, respectivamente, y getlocalport() y getport(), que devuelven los puertos local y remoto, respectivamente. A continuación se detallan brevemente los métodos mencionados. Puedes consultar más información sobre ellos en la web de Sun, que se cita al inicio de la práctica public int getport(): devuelve el puerto remoto al que el socket está conectado. public InetAddress getinetaddress(): devuelve la dirección IP remota a la que el socket está conectado. public int getlocalport(): devuelve el puerto local al que el socket está ligado. public InetAddress getlocaladdress(): Devuelve la dirección IP local a la que el socket está ligado. Ejercicio 3: Modifica el cliente ClienteTCP2.java del ejercicio anterior para que muestre información en la pantalla del cliente sobre la conexión que establece (direcciones IP y números de puerto locales y remotos). Ejecútalo cuatro veces seguidas, conectándote con el servidor del laboratorio zoltar.redes.upv.es en el puerto 25 y comprueba qué valores se modifican. Interpreta el resultado obtenido. 4. Cómo leer los datos que se reciben a través de la conexión Para leer los datos que se van recibiendo a través del socket utilizaremos el método getinputstream de la clase Socket. Este método devuelve un objeto del tipo InputStream (flujo de octetos de entrada), lo que se ajusta bien a la filosofía TCP de transmisión orientada a flujo continuo de datos, pero no resulta cómodo para leer los mensajes del servidor. Lo que nos conviene, para facilitar nuestro trabajo, es un método que proporcione un flujo de caracteres y, a ser posible, en líneas de texto completas. La clase InputStreamReader es un puente desde los flujos de bytes a los de caracteres: lee octetos y los codifica en caracteres empleando un código de caracteres determinado. Adicionalmente, para mejorar la eficiencia en la conversión pueden leerse varios octetos en cada operación

Introducción a los sockets en Java P3-5 de lectura anidando esta clase dentro de una BufferedReader. Por ejemplo, de la forma siguiente: BufferedReader lee = new BufferedReader(new InputStreamReader(s.getInputStream())); siendo s el objeto de la clase Socket definido previamente. Cuando un programa lee de un BufferedReader, el texto se extrae de un buffer en lugar de acceder al flujo de entrada directamente. Cuando el buffer se vacía, vuelve a llenarse con tanto texto como sea posible, incluso aunque no todo sea aún necesario. Esto hará que las futuras lecturas se lleven a cabo más rápidamente. En nuestro caso, empleando el método readline de la clase BufferedReader podremos leer las respuestas del servidor como líneas completas de texto. Este método lee una línea de texto y la devuelve como un String. public String readline() throws IOException Ejercicio 4: Renombra el cliente ClienteTCP2.java del ejercicio anterior como ClienteSMTP.java. Modíficalo para que se conecte siempre al puerto 25 y muestre la primera línea de texto que recibe del servidor. 5. Cómo enviar datos a través de la conexión Para escribir a través de un socket también es más eficiente utilizar una clase que proporcione cierta capacidad de almacenamiento (buffering). Por este motivo, para escribir a través del socket, utilizaremos un objeto de la clase java.io.printwriter conectado al flujo de salida del socket. Este objeto proporciona la capacidad de almacenamiento deseada. Además, esta clase permite manejar adecuadamente conjuntos de caracteres y texto internacional. Uno de sus constructores (el que utilizaremos habitualmente) es: public PrintWriter(OutputStream out, boolean autoflush) que además posee una ventaja importante como comprobaremos a continuación. Para ello el segundo parámetro del constructor debe invocarse con el valor true.

P3-6 Prácticas de Redes de Computadores 6. Vaciado del buffer TCP (flush) Aunque las ventajas de emplear para la escritura una clase con almacenamiento son claras, también puede plantear algunos inconvenientes si uno no es cuidadoso, como vamos a ver en el ejercicio siguiente. Ejercicio 5: Copia el programa ClienteSMTP.java y renómbralo como ClienteSMTPej5.java. Añade, al final de tu programa, el código siguiente: PrintWriter esc = new PrintWriter (s.getoutputstream()); salida.print("ehlo redesxx.redes.upv.es\r\n"); System.out.println( lectura 2: + lee.readline()); s.close(); NOTA: Se ha supuesto que el objeto BufferedReader definido en el ejercicio anterior se llama lee y el objeto Socket se llama s. Ejecútalo para que se conecte al puerto 25 de zoltar.redes.upv.es. Qué es lo que ocurre? Aparece la segunda respuesta del servidor en tu pantalla? (Lo normal será que no aparezca nada). Este cliente SMTP debería enviar un mensaje correcto al servidor SMTP de zoltar y recibir su respuesta, pero no recibe nada. Por qué? Porque él tampoco le envía nada. Para mejorar la eficiencia, el stream de salida intenta llenar su buffer tanto como sea posible antes de enviar los datos, pero como el cliente no tiene más datos que enviar (de momento) su petición no llega a enviarse nunca. La solución a este problema la da el método flush() de la clase PrintWriter. Este método fuerza a que se envíen los datos aunque el buffer no esté aún lleno. En caso de duda acerca de si resulta o no necesario utilizarlo, es mejor invocarlo, ya que realizar un flush innecesario consume pocos recursos, pero no utilizarlo cuando se necesita puede provocar bloqueos en el programa. Ejercicio 6: Modifica el cliente SMTP para que utilice el método flush y comprueba que ahora funciona correctamente.

Introducción a los sockets en Java P3-7 Podemos realizar el vaciado del buffer de forma automática al escribir en éste (sin tener que emplear el método flush explícitamente). Para ello necesitamos dos cosas: El constructor de la clase PrintWriter debe emplearse tal y como se ha mostrado antes, con un segundo parámetro adicional a true. La escritura debe realizarse mediante el método println(), en lugar del método print. Además el método println añade el final de línea con lo que no necesitamos escribirlo como parte de la orden que envía el cliente (a diferencia de lo que hemos hecho en el programa anterior). Vamos a modificar nuestro cliente para comprobar este funcionamiento. Ejercicio 7: Modifica el cliente SMTP para que utilice el método println en lugar del print (elimina lo que sobra, como la secuencia \r\n y el flush). Comprueba que funciona volviendo a establecer conexión con el servidor zoltar en el puerto 25. NOTA: Hay que tener en cuenta que cuando usamos el método println, lo que se envía como final de línea es \n. El estándar especifica que debe enviarse \r\n. No obstante, como podéis haber comprobado al usar println, el programa funciona correctamente. Esto es debido a la generosidad del servidor, que contesta a la petición a pesar de que no se ajusta completamente al estándar. Podemos ajustarnos fácilmente al estándar definiendo los finales de línea como \r\n con la sentencia System.setProperty ( line.separador, \r\n ); 7. Cierre de la conexión Las conexiones se cierran mediante el método close() de la clase Socket. Una vez que un socket se ha cerrado, ya no está disponible para volverlo a utilizar (por ejemplo, no puede ser reconectado). En caso necesario, hay que volver a crear un nuevo socket. Si este socket tenía un flujo asociado, el flujo se cierra también.

P3-8 Prácticas de Redes de Computadores 8. Explorador de puertos Está seguro nuestro ordenador? Es fácil entrar en él de forma no autorizada desde otro ordenador? Responder a esta pregunta es complicado. En general, sabemos que para entrar en nuestro ordenador desde otro equipo es necesario que en alguno de los puertos de nuestro ordenador haya un servidor escuchando. En el caso más extremo, si todos los puertos de nuestro ordenador están cerrados, tenemos la seguridad de que no vamos a aceptar datos que provengan de la red, por lo que evitamos la entrada no deseada de intrusos. Cerrar todos los puertos del ordenador puede no ser una buena idea, pues seguramente algunos de los servicios que usamos habitualmente (y de los cuales incluso no somos conscientes) dejarán de funcionar, con la correspondiente molestia. Una política más acertada es mantener abiertos únicamente los puertos que necesitamos y cerrar el resto. No obstante, a menudo el sistema operativo se configura con determinadas opciones por defecto, dejando abiertos algunos puertos que seguramente no deseamos que estén abiertos. En otros casos, es posible que un intruso haya abierto un puerto en nuestro ordenador y haya dejado en él un servidor, del cual no tenemos conocimiento. La mejor manera de saber qué puertos están abiertos en nuestro ordenador es usar un explorador de puertos. Realizar esta tarea en TCP es muy sencillo. Basta con recorrer los puertos de nuestro ordenador intentando conectarnos a ellos. Si un puerto nos permite conectarnos, significa que hay un servidor escuchando en él. Si rechaza la conexión, entonces el puerto está cerrado. En el caso de UDP, hacer la exploración no es tan sencilla, pues al ser un servicio sin conexión, si no recibimos contestación, nunca vamos a tener la seguridad de qué es lo que ha pasado con nuestro mensaje. Para crear el explorador de puertos nos vamos a valer de la clase Socket, que ya hemos empleado en los ejercicios anteriores. Como hemos visto, su constructor puede lanzar dos excepciones diferentes: UnknownHostException, que se genera cuando el nombre del ordenador con el que queremos crear la conexión no puede ser resuelto a una dirección IP. IOException, que se genera cuando no se puede establecer la conexión por cualquier otro motivo, como por ejemplo que no haya un

Introducción a los sockets en Java P3-9 servidor escuchando en el puerto especificado en los parámetros de Socket. Utilizaremos esta segunda excepción para crear el explorador de puertos, de manera que si mientras barremos los puertos de nuestro equipo se genera esta excepción, sabremos que el puerto está cerrado. Si no se genera, entonces es que hay un servidor en ese puerto. Como lo habitual es que la mayoría de los puertos se encuentren cerrados, nuestro explorador debe mostrar por pantalla un mensaje únicamente si el puerto está abierto. En caso contrario, suelen salir tantos mensajes que resulta difícil averiguar todos los puertos abiertos. Ejercicio 8: Teclea y completa el siguiente explorador de puertos. Ejecútalo. Qué puertos hay abiertos? A qué servicios corresponden esos puertos? (en /etc/services hay un listado detallado de los servicios ordenados por número de puerto). import java.net.*; import java.io.*; public class LowPortScanner { public static void main(string[] args) { String host = "localhost"; for (int puerto = 1; puerto < 1024; puerto ++) { try { // COMPLETAR CÓDIGO } catch (UnknownHostException e) { // COMPLETAR CÓDIGO } catch (IOException e) { // COMPLETAR CÓDIGO } } // end for } // end main } // end PortScanner Ejercicio 9: Elimina de tu ordenador todos los ficheros que has creado durante el desarrollo de esta práctica.