La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Tema II: Programación con sockets

Presentaciones similares


Presentación del tema: "Tema II: Programación con sockets"— Transcripción de la presentación:

1 Tema II: Programación con sockets
Luis López Fernández

2 Tema II: Programación con Sockets
Tema II: Contenidos 2.1: Introducción 2.2: Streams en Java 2.3: Sockets TCP 2.4: Sockets UDP 2.5: Sockets con entrada/salida asíncrona en Java Tema II: Programación con Sockets

3 Lección 2.1: Introducción
2.2: Streams en Java 2.3: Sockets TCP 2.4: Sockets UDP 2.5: Sockets con entrada/salida asíncrona en Java Tema II: Programación con Sockets

4 Tema II: Programación con Sockets
La API de sockets La API de sockets es un mecanismo que permite acceder a los servicios IPC proporcionados por los protocolos TCP y UDP Los sockets están en el nivel de abstracción del modelo de “paso de mensajes” Casi nadie desarrolla directamente sobre sockets hoy en día … …pero todas las APIs de mayor abstracción se basan en sockets Es importante comprender los detalles de la API de sockets La API de sockets está disponible en la inmensa mayoría de los sistemas En ocasiones forma parte del núcleo del sistema operativo (i.e. Unix) En ocasiones es una librería externa (i.e. API Winsock de Windows) Traducción de socket “enchufe, toma eléctrica” La metáfora es que el socket es un punto en el proceso (toma) al que otros procesos pueden “enchufar un cable” El “cable” representa una conexión o un flujo de datos Tema II: Programación con Sockets

5 Tema II: Programación con Sockets
La metáfora del socket Proceso A Proceso B Tema II: Programación con Sockets

6 Tema II: Programación con Sockets
La metáfora del socket Proceso A Proceso B CREATE SOCKET CREATE SOCKET Tema II: Programación con Sockets

7 Tema II: Programación con Sockets
La metáfora del socket Proceso A Proceso B PLUG SOCKET PLUG SOCKET Tema II: Programación con Sockets

8 Tema II: Programación con Sockets
La metáfora del socket Proceso A Proceso B SEND DATA RECEIVE DATA Tema II: Programación con Sockets

9 Tema II: Programación con Sockets
La metáfora del socket Proceso A Proceso B UNPLUG UNPLUG Tema II: Programación con Sockets

10 Lección 2.2: Streams en Java
2.1: Introducción 2.2: Streams en Java 2.3: Sockets TCP 2.4: Sockets UDP 2.5: Sockets con entrada/salida asíncrona en Java Tema II: Programación con Sockets

11 Tema II: Programación con Sockets
Streams Traducción de Stream “Corriente, chorro, flujo” El stream es una secuencia ordenada de unidades de información (bytes, caracteres, etc) que puede fluir en dos direcciones: hacia fuera de un proceso (de salida) o hacia dentro de un proceso (de entrada) Los streams están diseñados para acceder a los datos de manera secuencial Los streams no suelen estar preparados para realizar operaciones no secuenciales (volver hacia atrás, saltarse datos, realizar acceso aleatorio a datos, etc.) Los streams, en principio, van recorriendo una secuencia de datos (de entrada o de salida) y al mismo tiempo, la van “consumiendo”. Es decir, un dato leido/escrito no puede ser “desleido/desecrito” (nota: existen excepciones a esta regla) Pueden existir streams especializados en la lectura/escritura de determinados tipos de datos (bytes, enteros, flotantes, caracteres, objetos, etc.) Tema II: Programación con Sockets

12 Funcionamiento básico de un stream
de entrada Proceso E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

13 Funcionamiento básico de un stream
OPEN STREAM Stream de entrada E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

14 Funcionamiento básico de un stream
READ BYTE Stream de entrada E E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

15 Funcionamiento básico de un stream
READ BYTE Stream de entrada El E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

16 Funcionamiento básico de un stream
READ BYTE Stream de entrada El_ E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

17 Funcionamiento básico de un stream
READ BYTE Stream de entrada El_g E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

18 Funcionamiento básico de un stream
READ BYTE Stream de entrada El_ga E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

19 Funcionamiento básico de un stream
CLOSE STREAM Stream de entrada El_ga E l g a t o e s p e r ó u n r a t o , p e Secuencia de bytes almacenados en un fichero Tema II: Programación con Sockets

20 Streams, Readers y Writers en Java
En informática, existen dos mecanismos fundamentales para almacenar datos En formato texto Utiliza el carácter como unidad de almacenamiento El carácter es la representación de un símbolo “legible” por un humano En formato binario Utiliza el byte como unidad de almacenamiento Este formato no es, en general, legible por humanos En Java, existen clases “especialistas” para leer/escribir datos en estos formatos Lectura de streams de texto: Reader Escritura en steams de texto: Writer Lectura de streams binarios: InputStream Escritura en streams binarios: OutputStream Las cuatro clases mencionadas son abstractas (no se pueden instanciar directamente objetos de esa clase) Cada una de esas cuatro clases actúa como padre de una jerarquía de herencia En la citada jerarquía se han definido clases concretas “especialistas” en problemas concretos de entrada/salida de datos Todas las clases de la jerarquía forman parte del paquete java.io de la API estándar Tema II: Programación con Sockets

21 Jerarquía de herencia asociada a InputStream
Tema II: Programación con Sockets

22 Jerarquía de herencia asociada a OutputStream
Tema II: Programación con Sockets

23 Jerarquía de herencia asociada a Reader
Tema II: Programación con Sockets

24 Jerarquía de herencia asociada a Writer
Tema II: Programación con Sockets

25 Leyendo y escribiendo datos binarios con Streams
package es.urjc; import java.io.*; public class BasicDataStreams { //Los datos que vamos a escribir en un fichero private static byte[] primes = {1, 2, 3, 5, 7, 11, 13}; public static void readDataFile(String filename) throws IOException { FileInputStream fis = new FileInputStream(filename); int prime; while( (prime = fis.read()) != -1) System.out.println("He leido " + (byte)prime); fis.close(); } public static void writeDataFile(String filename) throws IOException { File file = new File(filename); FileOutputStream fos = new FileOutputStream(file); for(int i = 0; i < primes.length; i++){ fos.write(primes[i]); fos.flush(); fos.close(); ... Tema II: Programación con Sockets

26 Leyendo y escribiendo datos binarios con Streams
package es.urjc; import java.io.*; public class BasicDataStreams { ... public static void main(String[] args){ String filename = "primes.dat"; if(args.length == 1) filename = args[0]; try{ writeDataFile(filename); } catch(IOException ioe){ System.err.println("No se ha podido escribir en el fichero " + filename); } readDataFile(filename); Tema II: Programación con Sockets

27 Conectando streams para realizar entrada/salida
Cada tipo de stream es especialista en un tipo de entrada/salida Por ejemplo FileInputSteam: especialista en leer bytes de un fichero DataInputStream: especialista en leer datos complejos (enteros, flotantes, booleanos, etc.) de un stream de bytes Los streams se pueden “conectar” para combinar sus capacidades Especialista en leer datos complejos de streams de bytes Fichero en disco Especialista en leer bytes de ficheros Datos leídos 0101 1001 1101 FileInputStream DataInputStream 1,234 0,2345 2,23E-12 Hw bytes doubles ... FileInputStream fis = new FileInputStream("C:\\nombre\\fichero.dat"); DataInputStream dis = new DataInputStream(fis); dis.readInt(); dis.readFloat(); dis.readDouble(); dis.close(); Tema II: Programación con Sockets

28 Serialización y streams de objetos
Los Data*Streams son especialistas en algunos datos complejos (int, double, etc.) Los Object*Streams son especialistas en leer/escribir objetos en/desde streams Los Object*Streams se basan en el mecanismo de la serialización En Java, la serialización es el proceso por el que un objeto se transforma en una secuencia de bytes que lo representa La deserialización es proceso por el que se reconstruye un objeto previamente serializado a partir de una secuencia de bytes En Java, para que un objeto sea serializable, debe ser instancia de una clase que implemente la interfaz Serializable, esta interfaz no define ningún método class MiClase implements Serializable { //atributos y métodos ... MiClase miObjeto = new MiClase(); Objeto en memoria Objeto recuperado en memoria value = 14 name = “Hello” p=0.23 Serialización Deserialización value = 14 name = “Hello” p=0.23 Objeto serializado Tema II: Programación con Sockets

29 ObjectIntputStream y ObjectOutputStream
Especialista en transformar objetos en una secuencia de bytes (en serializar objetos) Debe estar “conectado” a un OutputStream que se especifica en construcción Ej: ObjectOutputStream oos = new ObjectOutputStream(outputStream) La serialización se realiza invocando el método void writeObject (Object obj) ObjectInputStream: Especialista en recuperar objetos desde una secuencia de bytes (en recuperar objetos previamente serializados) Debe estar “conectado” a un InputStream que se especifica en construcción Ej: ObjectInputStream ois = new ObjectInputStream(inputStream) La deserialización se logra invocando el método Object readObject() Ejemplo de clase serializable import java.util.ArrayList; public class Persona implements Serializable{ public String nombre; public int age; public ArrayList<Persona> friends; } Tema II: Programación con Sockets

30 Ejemplo de uso de Object/Input/Output/Streams
import java.io.*; public class BasicObjectStreams { private static void writePersona(String filename){ Persona p = new Persona(); p.name = "Luis"; p.age = 29; p.friends = null; try{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename)); oos.writeObject(p); oos.close(); } catch(IOException ioe ){ System.exit(-1); } private static Persona readPersona(String filename){ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); return (Persona)ois.readObject(); //Habría que cerrar con close() } catch(IOException ioe) { System.err.println(ioe.getMessage()); } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); return null; ... Tema II: Programación con Sockets

31 Ejemplo de uso de Object/Input/Output/Streams
import java.io.*; public class BasicObjectStreams { ... public static void main(String[] args){ String filename = "persona.dat"; if(args.length == 1) filename = args[0]; writePersona(filename); Persona p = readPersona(filename); System.out.println("p.name=" + p.name + " -- p.age=" + p.age); } # javac BasicObjectStreams.java # java BasicObjectStream p.name=Luis -- p.age=29 # ls ... persona.dat Tema II: Programación con Sockets

32 Tema II: Programación con Sockets
¿Qué se serializa? Los objetos que sean instancias de clases Serializable se pueden serializar Para que un atributo no se serialice, debe ser marcado como transient Multitud de atributos no pueden ser serializados y deben ser marcados como transient (por ejemplo, un FileInputStream) Se serializan todos los atributos que no sean transient ni static Si un atributo es una referencia a un objeto, el objeto se serializa Por tanto, la serialización de un objeto con referencias crea un árbol de serialización Al deserializar el objeto, se recupera el árbol completo de objetos Si hay varias referencias a un objeto, los datos del mismo se serializan solo una vez Objeto A Objeto B Objeto A Objeto B Objeto D Objeto D transient Serialización Objeto A Deserialización Objeto A Objeto C Objeto E Objeto E Tema II: Programación con Sockets

33 Readers, writers y charsets
La entrada/salida de caracteres de texto es compleja debido a la gran cantidad de formatos de codificación que existen (ASCII, UTF-8, Unicode, etc.) Hacer entrada/salida de texto directamente con streams es complejo Los Readers y los Writers simplifican enormemente la tarea Como en el caso de los streams, existen clases especialistas en tareas concretas Para entenderlas hay que comprender cómo Java procesa y representa caracteres En Java, los caracteres se representan internamente en formato Unicode de 16 bits Cuando se lee un carácter, este se convierte de su formato nativo a Unicode Cuando se escribe un carácter, este se convierte de Unicode a su formato objetivo En Java, al formato nativo/objetivo de una cadena se le denomina su charset Desde Java 1.5 existe la clase Charset (en el paquete java.nio.charset) que permite operar sobre la representación de caracteres En Java, se soportan múltiples charsets de entrata/salida, entre los que se incluyen: US-ASCII, ISO , UTF-8, UTF-16BE, UTF-816LE, etc. Cada instancia de la máquina virtual tiene un charset por defecto que depende del formato utilizado por el sistema operativo subyacente El charset por defecto se puede averiguar mediante el método estático defaultCharset() de la clase Charset Tema II: Programación con Sockets

34 Algunos Readers y Writers
Vamos a ver algunos Readers y Writers básicos y en qué se especializan InputStreamReader Hace de “puente” entre streams de bytes y de caracteres Debe estar conectado con un InputStream que se especifica en construcción Tiene constructores que permiten especificar un Charset de preferencia Los constructores que no toman un Charset, usan el charset por defecto Puede leer caracteres de uno en uno utilizando el método int read() OutputStreamWriter Equivalente al InputStreamReader pero para salida de caractéres Escribe caractéres usando el método write(int c) InputStreamReader Hijos de InputStream bytes chars OutputStreamWriter Hijos de OutputStream bytes chars Tema II: Programación con Sockets

35 Algunos Readers y Writers
BufferedReader Permite leer texto de forma eficiente a través de un buffer intermedio Debe estar conectado con un Reader que se especifica en construcción Se utiliza el Charset que posea ese Reader Puede leer líneas completas utilizando el método String readLine() PrintWriter Imprime texto formateado Puede estar conectado a un Writer Puede estar conectado a un OutputStream Puede volcar directamente sobre un fichero Existen constructores para cada uno de los casos Se pueden imprimir líneas completas usando el método println(String line) InputStreamReader isr = new InputStreamReader(new FileOutputStream(“C:\\file.txt”); BufferedReader br = new BufferedReader(isr); String line = br.readLine(); ... PrintWriter pw = new PrintWriter(“C:\\file.txt”); pw.println(“Hola mundo”); Tema II: Programación con Sockets

36 Tema II: Programación con Sockets
Lección 2.3: Sockets TCP 2.1: Introducción 2.2: Streams en Java 2.3: Sockets TCP 2.4: Sockets UDP 2.5: Sockets con entrada/salida asíncrona en Java Tema II: Programación con Sockets

37 La API de sockets en modo stream (TCP sockets)
La API de sockets en modo stream proporciona acceso al servicio de transporte de datos proporcionado por el protocolo TCP El servicio TCP es orientado a conexión proporciona un transporte fiable La conexión se establece Un flujo de bytes sale del emisor El mismo flujo de bytes es recibido en el receptor El servicio proporcionado por el socket es full-duplex (el mismo socket puede ser utilizado para enviar y para recibir datos) Para que la conexión se pueda establecer, Uno de los sockets debe estar “a la espera de recibir conexiones” El otro socket debe “iniciar una conexión” Para que una conexión se libere (cierre) Basta con que uno de los sockets desee cerrarla Un socket recién creado no está conectado Vamos a estudiar en detalle el funcionamiento de los sockets TCP utilizando la funcionalidad proporcionada por la API estándar de Java Tema II: Programación con Sockets

38 Tipos de stream socket en Java
En Java hay dos tipos de stream sockets que tienen asociadas sendas clases ServerSocket Proporciona un socket dispuesto a aceptar conexiones TCP de forma pasiva Para simplificar, lo denominaremos socket de conexión Al proceso que posee un ServerSocket se le denomina también servidor Socket Proporciona un socket por el que se pueden intercambiar datos con otro socket Para simplificar, lo denominaremos socket de datos Al proceso que inicia una conexión desde un Socket se le denomina cliente El proceso a seguir para lograr el intercambio de datos es: El servidor crea el ServerSocket y lo asocia a un puerto El cliente crea un Socket El cliente ordena a su Socket que se conecte con el ServerSocket remoto Al recibir la petición, el servidor crea un nuevo Socket y lo connecta con el remoto Se intercambian los datos La conexión se cierra cuando alguno de los dos sockets lo indica Tema II: Programación con Sockets

39 Tema II: Programación con Sockets
La clase ServerSocket La clase ServerSocket forma parte del paquete java.net de la API estándar Constructores: ServerSocket(): Crea un nuevo socket de conexión no atado a ningún puerto ServerSocket(int port): Crea un nuevo socket de conexión y lo ata al puerto especificado. En número de puerto debe estar comprendido entre 0 y inclusive. Si port es 0, se toma un puerto libre “al azar” ServerSocket(int port, int backlog): Permite además especificar el tamaño de la cola de solicitudes de conexión no atendidas. Si el número de solicitudes no atendidas supera el tamaño especificado se rechazán solicitudes de conexión ServerSocket(int port, int backlog, InetAddress bindAddr): Permite además especificar la dirección IP en la que se atenderán las solicitudes de conexión (para ordenadores que dispongan de varias). Si bindAddr es null, el ServerSocket atenderá solicitudes de conexión en todas las interfaces de la máquina Tema II: Programación con Sockets

40 La clase ServerSocket Cont.
Algunos Métodos: Socket accept(): Escucha una solicitud de conexión y la acepta cuando se recibe. En ese momento, se crea nuevo Socket que es el que realmente se conecta con el cliente. Tras esto, el ServerSocket sigue disponible para realizar nuevos accept() void bind(SocketAddress endpoint): Ata al ServerSocket a la dirección especificada (dirección IP y puerto). El ServerSocket no debe estar atado previamente int getLocalPort(): Devuelve el puerto al que está atado el ServerSocket void close(): Cierra el ServerSocket ... ServerSocket serverSocket = new ServerSocket(0); System.out.println(“El puerto es “ + serverSocket.getLocalPort()); Socket connection = serverSocket.accept(); //hacemos cosas con connection Socket otherConnection = serverSocket.accept(); //hacemos cosas con otherConnection serverSocket.close(); Tema II: Programación con Sockets

41 Tema II: Programación con Sockets
La clase Socket La clase Socket forma parte del paquete java.net de la API estándar Algunos Constructores: Socket(): Crea un nuevo socket sin conectar Socket(InetAddress address, int port): Crea un nuevo socket y lo conecta automáticamente con un socket remoto en la dirección IP y puertos especificados Socket(InetAddress address, int port, InetAddress localAddr, int localPort): Permite además especificar la dirección IP local y el puerto local a los que se asociará el socket Socket(String host, int port): El host remoto se puede especificar a través de su nombre de dominio. Se utilizarán los mecanismos de resolución del sistema operativo subyacente Socket(Proxy proxy): Se crea un socket no conectado especificando el tipo de proxy que se desea usar Tema II: Programación con Sockets

42 Tema II: Programación con Sockets
La clase Socket Cont. Algunos Métodos: void connect(SocketAddress endpoing): Conecta este socket al servidor especificado (dirección IP y puerto) InetAddress getInetAddress(): Devuelve la dirección (IP y puerto) a la que este socket se encuentra conectado InputStream getInputStream(): Devuelve un InputStream que permite leer bytes del socket (recibir datos enviados desde el socket remoto) utilizando los mecanismos habituales de los streams. El socket debe estar conectado OutputStream getOutputStream(): Devuelve un OutputStream que permite escribir bytes sobre el socket (enviar bytes al socket remoto) utilizando los mecanismos habituales de los streams. El socket debe estar conectado void setKeepAlive(): Al activarlo, se chequea que la conexión entre dos sockets sigue activa enviando “paquetes basura” periódicamente (RFC 1122) void setSoLinger(boolean on, int linger): Al activarlo, si hay datos pendientes de enviar cuando se invoca close(), el llamante se bloquea (durante un máximo de linger segundos) hasta que los datos pendientes han sido enviados void setTcpNoDelay(): Permite activar/desactivar el algoritmo de Nagle para el envío en TCP (RFC 896) void setTrafficClass(int tc): Permite seleccionar el byte TOS del paquete IP (no todas las redes lo tienen en cuenta) Más información en RFC 1349 Tema II: Programación con Sockets

43 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

44 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket ServerSocket server = new ServerSocket(); La creación del ServerSocket no requiere ninguna sincronización entre servidor y cliente, la operación es no -bloqueante Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

45 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket Socket socket = serverSocket.accept(); La llamada a accept() es síncrona y bloquea al hilo llamante hasta que se recibe una solicitud de conexión destinada al proceso servidor (dirección IP y puerto). Cuando se recibe la citada solicitud, se crea un nuevo socket que sirve como extremo de la conexión junto con el socket remoto del cliente Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

46 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket Socket client = new Socket(host, port); La creación del socket cliente con este constructor requiere el establecimiento de la conexión, motivo por el cual esta llamada es bloqueante, haciendo que el hilo cliente se bloquee hasta que el establecimiento de la conexión haya finalizado. Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

47 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket socket.getInputStream()read() La llamada a read() sobre el InputStream del socket es bloqueante, el hilo se detiene mientras no se reciban los datos enviados por el proceso remoto. Si se especifica un tamaño de datos esperado, la llamada se bloquea hasta que se reciben suficiente información desde el socket remoto (i.e. readLine()) Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

48 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket socket.getOutputStream()write() La llamada a write() sobre el OutputStream del socket es bloqueante, el hilo se detiene mientras TCP haya recibido el asentimiento de los datos enviados. Puede que una llamada a write() se desbloquee sin que se haya producido un read() en el proceso remoto, pero esto sólo sucede cuando los datos enviados “caben” en la ventana TCP del receptor Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

49 Sincronización de cliente y servidor
server = new ServerSocket() server.accept() socket.close() Las llamadas a cloase() son siempre no-bloqueantes, excepto cuando SO_LINGER se ha activado sobre el socket, En cuyo caso la llamada es bloqueante hasta que se terminan de enviar los datos pendientes client = new Socket(host, port) Conexión Nuevo Socket conectado read() sobre el Socket write() sobre el socket Mensaje read() sobre el socket write() sobre el Socket Mensaje socket.close() socket.close() serverSocket.close() Tema II: Programación con Sockets

50 Java stream sockets: ejemplo de aplicación
import java.io.*; import java.net.*; public class BasicServer { public static void main(String[] args) throws IOException { int port = 2345; if(args.length == 1) port = Integer.parseInt(args[0]); BasicServer server = new BasicServer(port); server.launch(); } private ServerSocket serverSocket; private BasicServer(int port) throws IOException { serverSocket = new ServerSocket(port); private void launch() throws IOException { while(true){ Socket connection = serverSocket.accept(); BufferedReader br = new BufferedReader( new InputStreamReader(connection.getInputStream())); String inputMessage = br.readLine(); PrintWriter pw = new PrintWriter(connection.getOutputStream()); pw.println(inputMessage.toUpperCase()); pw.close();//si no se cierra primero, hay que hacer flush br.close(); connection.close(); Tema II: Programación con Sockets

51 Java stream sockets: ejemplo de aplicación
import java.io.*; import java.net.*; public class BasicClient { public static void main(String[] args) throws Exception { String remoteHost = "localhost"; int remotePort = 2345; BasicClient client = new BasicClient(remoteHost, remotePort); client.launch(); } private String host; private int port; private static final String message = "mensaje básico en iteración "; private BasicClient(String host, int port) throws IOException { this.host = host; this.port = port; private void launch() throws Exception { for(int iteration = 0; iteration < 10; iteration++){ Socket connection = new Socket(host, port); PrintWriter pw = new PrintWriter(connection.getOutputStream()); pw.println(message + iteration); pw.flush(); System.out.println(">>>>>" + message + iteration); BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); System.out.println("<<<<<" + br.readLine()); pw.close(); br.close(); connection.close(); Thread.sleep(1000); Tema II: Programación con Sockets

52 Tema II: Programación con Sockets
Lección 2.4: Sockets UDP 2.1: Introducción 2.2: Streams en Java 2.3: Sockets TCP 2.4: Sockets UDP 2.5: Sockets con entrada/salida asíncrona en Java Tema II: Programación con Sockets

53 La API de sockets en modo datagama (UDP sockets)
La API de sockets en modo datagrama proporciona acceso al servicio de transporte de datos que implementa el protocolo UDP El servicio UDP no es orientado a conexión ni proporciona entrega fiable de datos El emisor envía un datagrama a un proceso remoto (dirección IP y puerto) Si el datagrama no se pierde, eventualmente será recibido en el receptor La API estándar de Java proporciona sockets orientados a datagrama que permiten utilizar directamente el servicio UPD que acabamos de describir Un socket en modo datagrama proporciona un servicio full-duplex Java también proporciona una abstracción adicional que provee de un servicio de transporte no fiable orientado a conexión basado en el protocolo UPD. Esta abstracción forma parte del runtime de Java y no supone modificación alguna sobre el funcionamiento del protocolo UDP Todos los paquetes que pertenecen a una de estas conexiones lógicas comparten 4 parámetros (el runtime de Java asigna paquetes a conexiones usándolos): Puerto de origen, Dirección IP de origen, Puerto de destino, Dirección IP de destino Vamos a estudiar en detalle el funcionamiento de los sockets UDP utilizando la funcionalidad proporcionada por la API estándar de Java Tema II: Programación con Sockets

54 La clase DatagramSocket
La clase DatagramSocket forma parte del paquete java.net de la API estándar Constructores: DatagramSocket(): Crea un socket de datagrama y lo ata a un puerto libre en la máquina local. Este constructor suele crearse para desarrollar el extremo cliente de una aplicación. DatagramSocket(int port): Crea un nuevo socket de datagrama y lo ata al puerto especificado en todas las interfaces de la máquina local. Este constructor suele utilizarse para desarrollar el extremos servidor de una aplicación DatagramSocket(int port, InetAddress laddr): Crea un nuevo socket de datagrama y lo ata al puerto especificado en la dirección IP dada sobre la máquina local (para máquinas con varias interfaces). Este constructor suele utilizarse para crear el extremo servidor de una aplicación DatagramSocket(SocketAddress bindaddr): Crea un nuevo socket de datagrama y lo ata a la dirección especificada (puerto y dirección IP). Este constructor suele utilizarse para crear el extremos servidor de una aplicación Tema II: Programación con Sockets

55 La clase DatagramSocket
Algunos métodos: void bind(SocketAddress addr): Ata el socket de datagrama a la dirección especificada (puerto y dirección IP) int getLocalPort(): Devuelve el puerto al que el socket está atado void receive(DatagramPacket p): Recibe un datagrama en el socket. Esta llamada es bloqueante. Cuando este método retorna, los datos se devuelven en el buffer del DatagramPacket. El DatagramPacket también contiene la dirección IP y el puerto del emisor. void send(DatagramPacket p): Envía un datagrama desde el socket. El DatagramPacket contiene los datos, su longitud, la dirección IP del receptor y su número de puerto void setTraffciClass(int tc): Permite establecer es campo TOS (type-of-service) de los paquetes IP que encapsulan los datagramas (RFC 1349) void close(): Cierra el socket, no se podrán volver a enviar ni a recibir datragamas desde el socket Tema II: Programación con Sockets

56 La clase DatagramPacket
La clase DatagramPacket forma parte del paquete java.net de la API estándar Constructores: DatagramPacket(byte[] buf, int length): Construye un DatagamPacket para recibir datagramas con hasta length bytes de datos DatagramPacket(byte[] buf, int length, InetAddress addr, int port): Crea un nuevo DatagramPacket para el envío de los datos especificados a la dirección y puerto remotos dados DatagramPacket(byte[] buf, int offset, int length): Construye un DatagramPacket para la recepción de datos, que se depositarán con el offset especificado en el buffer dado DatagramPacket(byte[] buf, int offset, int length, InetAddress addr, int port): Crea un DatagramPacket para enviar un datagrama UPD que contenga length bytes de datos a partir de buf[offset] Tema II: Programación con Sockets

57 La clase DatagramPacket
Algunos métodos: InetAddress getAddress(): Cuando el DatagramPacket es para envío, indica la dirección IP del receptor, cuando el DatagramPacket es de recepción, indica la dirección IP del emisor (siempre la dirección IP del lado remoto) byte[] getData(): Devuelve el buffer de datos asociado a este DatagramPacket. Si el DatagramPacket es de recepción, el buffer contendrá los datos recibidos int getLength(): Devuelve en número de bytes útiles en el datagrama. Este método permite determinar los bytes de datos útiles que se pueden extraer del buffer devuelto por getData() int getPort(): Cuando el DatagramPacket es para envío, indica el puerto receptor, cuando el DatagramPacket es de recepción, indica el puerto del emisor (siempre el puerto del lado remoto) void setData(byte[] buf): Permite asociar un nuevo buffer de datos con el DatagramPacket. Si el DatagramPacket es de recepción, los datos del datagrama recibido no podrán exceder buf.length, en caso contrario, los datos se truncarán void setLength(int length): Indica el número de bytes útiles en el buffer asociado al DatagramPacket. Este método es usado cuando el DatagramPacket es de emisión para indicar cuantos bytes del buffer especificado se enviarán en el datagrama correspondiente void setPort(int port): Indica el puerto asociado a un DatagramPacket. Este método se usa para indicar el puerto del receptor el datagramas de envío Tema II: Programación con Sockets

58 Sincronización de los DatagramSocket
Servidor Cliente server = new DatagramSocket(2345) client = new DatagramSocket() server.receive(datagramPacket) client.send(datagramPacket) Mensaje client.receive(datagramPacket) server.send(datagramPacket) Mensaje server.close() client.close() Tema II: Programación con Sockets

59 Sincronización de los DatagramSocket
Servidor Cliente server = new DatagramSocket(2345) client = new DatagramSocket() server.receive(datagramPacket) client.send(datagramPacket) Mensaje client.receive(datagramPacket) server.send(datagramPacket) DatagramSocket server = new DatagramSocket(2345); La creación de un DatagramSocket atado a un puerto es no -bloqueante Mensaje server.close() client.close() Tema II: Programación con Sockets

60 Sincronización de los DatagramSocket
Servidor Cliente server = new DatagramSocket(2345) client = new DatagramSocket() server.receive(datagramPacket) client.send(datagramPacket) Mensaje client.receive(datagramPacket) server.send(datagramPacket) server.receive(datagramPacket); La llamada a receive en un DatagramSocket es una operación síncrona y, por tanto, bloqueante Mensaje server.close() client.close() Tema II: Programación con Sockets

61 Sincronización de los DatagramSocket
Servidor Cliente server = new DatagramSocket(2345) client = new DatagramSocket() server.receive(datagramPacket) client.send(datagramPacket) Mensaje client.receive(datagramPacket) server.send(datagramPacket) client.send(datagramPacket); La llamada a send en un DatagramSocket es una operación no-bloqueante, el paquete se envía pero so se espera ningún asentimiento Mensaje server.close() client.close() Tema II: Programación con Sockets

62 Sincronización de los DatagramSocket
Servidor Cliente server = new DatagramSocket(2345) client = new DatagramSocket() server.receive(datagramPacket) client.send(datagramPacket) Mensaje client.receive(datagramPacket) server.send(datagramPacket) Mensaje Cuando el mensaje se recibe, se desbloquea la llamada al método receive de la clase DatagramSocket server.close() client.close() Tema II: Programación con Sockets

63 Sincronización de los DatagramSocket
Servidor Cliente server = new DatagramSocket(2345) client = new DatagramSocket() datagramSocket.close(); Las llamadas al método close son siempre no -bloqueante server.receive(datagramPacket) client.send(datagramPacket) Mensaje client.receive(datagramPacket) server.send(datagramPacket) Mensaje server.close() client.close() Tema II: Programación con Sockets

64 Java Datagram Sockets: ejemplo de aplicación
import java.io.*; import java.net.*; public class BasicUDPServer { public static void main(String[] args) throws IOException { DatagramSocket udpSocket = new DatagramSocket(2345); DatagramPacket datagramReceived = new DatagramPacket(new byte[512], 512); while(true){ udpSocket.receive(datagramReceived); String messageReceived = new String(datagramReceived.getData(), 0 , datagramReceived.getLength()); byte[] answer = messageReceived.toUpperCase().getBytes(); DatagramPacket datagramSent = new DatagramPacket( answer, answer.length, datagramReceived.getAddress(), datagramReceived.getPort()); udpSocket.send(datagramSent); } Tema II: Programación con Sockets

65 Java Datagram Sockets: ejemplo de aplicación
import java.net.*; public class BasicUDPClient { private final static String message = "el cliente envia el mensaje "; public static void main(String[] args) throws Exception { DatagramSocket udpSocket = new DatagramSocket(); for(int i = 0; i< 10; i ++){ String messageSent = message + i; byte[] datos = messageSent.getBytes(); DatagramPacket datagram = new DatagramPacket( datos, datos.length, InetAddress.getByName("localhost"), 2345); udpSocket.send(datagram); System.out.println(">>>>>" + messageSent); datagram = new DatagramPacket(new byte[512], 512); udpSocket.receive(datagram); String messageReceived = new String(datagram.getData(), 0, datagram.getLength()); System.out.println("<<<<<" + messageReceived); Thread.sleep(1000); } Tema II: Programación con Sockets

66 Java DatagramSockets orientados a conexión
La clase DatagramPacket proporciona una abstracción de envío de datagramas no fiable con orientación a conexión Métodos implicados: void connect(InetAddress address, int port): Conecta el DatagramSocket a la dirección remota especificada. Una vez conectado, el socket sólo podrá enviar o recibir datagramas de la dirección remota especificada. Si se envía o recibe un datagrama con dirección IP o puerto remoto diferentes, se elevará una excepción IllegalArgumentException. En algunos sistemas, si el socket remoto no existe en la dirección especificada, o si éste no se puede alcanzar, el DatagramSocket local recibirá un paquete ICMP (destination unreachable), lo que se notificará con una excepción PortUnreachableException en cualquier llamada a send() or receive() void disconnect(): Desconecta el DatagramSocket boolean isConnected(): Devuelve true si el socket está conectado, false en caso contrario Tema II: Programación con Sockets

67 Lección 2.5: Sockets con entrada/salida asíncrona en Java
2.1: Introducción 2.2: Streams en Java 2.3: Sockets TCP 2.4: Sockets UDP 2.5: Sockets con entrada/salida asíncrona en Java Tema II: Programación con Sockets

68 Operaciones bloqueantes en los sockets de Java
Socket TCP Socket UDP server = new ServerSocket() client = new DatagramSocket() server.accept() client.send(datagramPacket) Nuevo Socket conectado read() sobre el Socket client.receive(datagramPacket) write() sobre el Socket socket.close() client.close() serverSocket.close() Tema II: Programación con Sockets

69 Problemas de las llamadas bloqueantes Proceso origen en espera
Las llamadas bloqueantes facilitan la sincronización entre los procesos que comunican, pero complican algunos aspectos del desarrollo En ciertas condiciones producen el bloqueo indefinido de un proceso datagramSocket.receive(datagramPacket) + pérdida del mensaje emitido datagramSocket.receive(datagramPacket) + crash del proceso emisor serverSocket.accept() + crash del proceso remoto Pueden producir interbloqueo entre los procesos que comunican Para procesos que deben mantener varias comunicaciones simultáneas, requieren el uso intensivo de hilos de ejecución (threads) Los hilos limitan la escalabilidad del sistema La gestión de muchos hilos hace menos eficiente el programa Las llamadas bloqueantes dificultan la destrucción y reutilización de hilos Proceso A Proceso B Proceso origen en espera de proceso destino Proceso C Tema II: Programación con Sockets

70 Uso de bloqueos con temporizador
Para evitar los bloqueos indefinidos y permitir que los procesos puedan “reaccionar” ante situaciones “especiales”, Java proporciona la posibilidad de establecer temporizadores asociados a las llamadas bloqueantes Estos temporizadores funcionan del modo siguiente: El usuario elige un “tiempo máximo” (a través de una invocación) Cuando se produce la invocación al método bloqueante, se inicia un temporizador Si el método bloqueante retorna (es decir, se desbloquea) antes de que se alcance el “tiempo máximo”, el programa continúa con normalidad Si se alcanza el “tiempo máximo” sin que la llamada retorne, se eleva una excepción desde dentro del método bloqueante En todos los casos, el agotamiento del temporizador y el lanzamiento de la excepción correspondiente no afecta al estado del socket correspondiente El desarrollador tiene la opción de manejar la excepción y dejar al programa continuar, o bien de tomar acciones adicionales que pueden incluir el cierre y destrucción del socket. Tema II: Programación con Sockets

71 Estableciendo el tiempo de espera máximo
Estableciendo el tiempo máximo de espera en la clase ServerSocket serverSocket.setSoTimeout(int tiemout) tiemout especifica el tiempo máximo de espera en milisegundos. Un valor de 0 indica un tiempo de espera infinito Afecta a las llamadas a serverSocket.accept(). Si el timeout se agota, se elevará una excepción java.net.SocketTimeoutException Estableciendo el tiempo máximo de espera en la clase Socket Afecta a las llamadas a read() en el InputStream asociado al socket. Si el timeout se agota, se elevará una java.net.SocketTimeoutException Estableciendo el tiempo máximo de espera en la clase DatagramSocket Afecta a las llamadas a datagramSocket.receive(p). Si el timeout se agota, se elevará una java.net.SocketTimeoutException Tema II: Programación con Sockets

72 Ejemplo de desarrollo con temporizadores
Queremos que un proceso (o hilo) no se bloquee de manera indefinida Usamos temporizadores para desbloquearlo de manera periódica Cada cierto tiempo chequeamos si el necesario “continuar con otra cosa” import java.net.*; import java.io.*; public class TimeoutServerSocket { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(2345); server.setSoTimeout(250); //El valor del timeout depende de la aplicación boolean continuar = true; while(continuar){ try{ Socket connection = server.accept(); //Hacer cosas con la conexión //Podemos hacer continuar = false } catch(SocketTimeoutException ste){ //Chequear si debemos continuar //Podemos elevar una excepción //Podemos cerrar el socket y hacer continuar = false } Tema II: Programación con Sockets

73 Desarrollo con entrada/salida asíncrona
El modelo basado en temporizadores es una solución a medias No evita el uso de múltiples hilos de ejecución Si se quieren tiempos de respuesta bajos (timeouts pequeños) se degradan las prestaciones Si se quieren prestaciones elevadas (timeouts grandes) se degradan los tiempos de respuesta Muchos lenguajes de programación/entornos de desarrollo ofrecen operaciones de entrada salida asíncronas Las operaciones de entrada/salida asíncronas ofrecen servicios de lectura y escritura no bloqueantes La estrategia habitual para desarrollar programas con entrada/salida asíncrona se basa en el uso de modelos de programación orientados a eventos El programa es un bucle a la espera de eventos Cuando se producen eventos, el bucle realiza una iteración para procesarlos Puede usarse un único hilo de ejecución o varios para procesar los eventos Java define un conjunto de facilidades de entrada/salida asíncronas en el paquete java.nio (Java New Input Output) que existe desde el JDK 1.4 Vamos a ver los fundamentos de estas facilidades, pero no profundizaremos Tema II: Programación con Sockets

74 Tema II: Programación con Sockets
Java New Input Output El paquete java.nio proporciona facilidades para el desarrollo de aplicaciones que requieran entrada/salida de alta velocidad y/o altas prestaciones Delega algunas de las partes más tediosas (gestión de bufferes) al sistema nativo El modelo de streams (definido en java.io) se basa en corrientes de bytes, el modelo de java.nio, se basa en bloques que se almacenan en bufferes En java.nio existen dos conceptos (objetos) esenciales Channel: Es un objeto análogo a un stream, pero bidireccional (se puede leer y escribir sobre el mismo objeto) y que funciona sobre bloques y no sobre bytes Buffer: Es el objeto que se utiliza como contenedor de bloques para los channels En java.nio todos los datos que se leen o escriben se gestionan a través de un objeto Buffer Además de contener los datos, el objeto Buffer proporciona facilidades al programador que facilitan el desarrollo de aplicaciones Existen diferentes tipos de buffers “especialistas” en diferentes tipos de datos: Tema II: Programación con Sockets

75 Tema II: Programación con Sockets
Bufferes en java.nio La clase java.nio.Buffer es abstracta Para cada tipo de datos primitivos existe una subclase especialista: ByteBuffer, CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer y DoubleBuffer El Buffer contiene un bloque (array) de datos de entrada/salida que puede ser manipulado a través de métodos específicos El funcionamiento de estos métodos se basa en tres variables de estado La variable position Especifica la siguiente posición del array que será escrita/leída En cada operación de lectura/escritura, position se incrementa en una unidad La variable limit Especifica cuantas posiciones del array pueden ser leidas/escritas en total Es decir, indica cuanto espacio tiene el array para lectura/escritura Siempre se cumple que position <= limit La variable capacity Especifica la máxima cantidad de elementos que caben en el array Es decir, indica el tamaño en memoria del array subyacente Siempre se cumple que limit <= capacity Tema II: Programación con Sockets

76 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); position limit capacity Tema II: Programación con Sockets

77 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); position limit capacity a Tema II: Programación con Sockets

78 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); position limit capacity a b Tema II: Programación con Sockets

79 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); position limit capacity a b c Tema II: Programación con Sockets

80 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); position limit capacity a b c Tema II: Programación con Sockets

81 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); c =‘a’ position limit capacity a b c Tema II: Programación con Sockets

82 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); c =‘b’ position limit capacity a b c Tema II: Programación con Sockets

83 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); c =‘c’ position limit capacity a b c Tema II: Programación con Sockets

84 Bufferes en java.nio: Ejemplo de uso
CharBuffer charBuffer = CharBuffer.allocate(5); charBuffer.put('a'); charBuffer.put('b'); charBuffer.put('c'); charBuffer.flip(); char c = charBuffer.get(); c = charBuffer.get(); throws java.nio.BufferUnderflowException position limit capacity a b c Tema II: Programación con Sockets

85 Tema II: Programación con Sockets
Channels en java.nio Channel es una interfaz definida en el paquete java.nio.channels El Channel representa una conexión abierta hacia una entidad sobre la que se puede realizar entrada/salida de datos Un Channel recién creado está abierto, una vez que se cierra no es posible realizar operaciones posteriores de entrada/salida. Se puede saber si un Channel está abierto invocando el método (de la interfaz) isOpen() La interfaz Channel cuenta con un conjunto de subinterfaces y de clases que la implementan Algunas Subinterfaces: ByteChannel, InterruptibleChannel, ReadableByteChannel, WritableByteChannel, etc. Algunas clases que lo implementan: FileChannel: Especialista en asociarse a FileStreams para entrada/salida SocketChannel: Especialista en asociarse a instancias de la clase Socket ServerSocketChannel: Especialista en asociarse a instancias de ServerSocket DatagramChannel: Especialista en asociarse a instancias de DatagramSocket SelectableChannel: Channel que puede ser multiplexado a través de un Selector. Es superclase de todos los Channels que tienen que ver con Sockets Tema II: Programación con Sockets

86 Ejemplo de uso de la clase FileChannel
import java.io.*; import java.nio.*; import java.nio.channels.*; public class FileChannelExample { private static final String FILENAME = "channelFile.dat"; private static final String MESSAGE = "hola nena"; public static void main(String[] args) throws IOException { writeFileWithChannel(); readFileWithChannel(); } public static void writeFileWithChannel() throws IOException { FileOutputStream fos = new FileOutputStream(FILENAME); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); buffer.put(MESSAGE.getBytes("ISO ")); buffer.flip(); FileChannel ch = fos.getChannel(); ch.write(buffer); ch.close(); public static void readFileWithChannel() throws IOException { FileInputStream fis = new FileInputStream(FILENAME); FileChannel ch = fis.getChannel(); ch.read(buffer); byte[] data = new byte[buffer.remaining()]; buffer.get(data); String message = new String(data, "ISO "); Tema II: Programación con Sockets

87 Entrada/Salida asíncrona con Sockets en Java
Este mecanismo permite leer/escribir sobre un socket de red sin bloqueos El modelo de programación se basa en eventos Hay que registrar “interés” por un evento de entrada/salida determinado Cuando el evento “sucede”, el sistema informa del mismo Se procesa el evento ocurrido Se vuelve a esperar por eventos La clase Selector se utiliza para la gestión de eventos en subclases de SelectableChannels Selector es una clase abstracta que proporciona un multiplexor de channels Un SelectableChannel que se registra en un Selector, queda representado mediante un objeto de la clase SelectionKey Las instancias de SelectionKey tienen múltiples métodos de interés SelectableChannel channel(): recupera el channel asociado a la key Selector selector(): recupera el Selector en que se creó la key Al registrar el SelectableChannel hay que especificar los eventos de interés Cuando todos los channels y sus eventos se han registrado, el Selector está listo Tema II: Programación con Sockets

88 Tema II: Programación con Sockets
Uso de selectores Partimos de instancias de subclases de SelectableChannel Abrimos un Selector Registramos los channels declarando los eventos de nuestro interés Los eventos de interés son enteros potencias de dos Se pueden activar varios eventos usando el operador | (bitwise) SelectionKey.OP_ACCEPT: Cuando se ha recibido una solicitud de conexión SelectionKey.OP_CONNECT: Cuando se ha concluido el establecimiento de una conexión o bien cuando hay un error que afecta la conexión SelectionKey.OP_READ: Cuando se puede leer SelectionKey.OP_WRITE: Cuando se puede escribir El Selector tiene un método select() cuya invocación es bloqueante. Sólo retorna cuando se da alguna de las condiciones siguientes: Ocurre (al menos) un evento de interés sobre alguno de los canales registrados Se interrumpe el hilo llamante (mediante llamada a interrupt()) Se invoca el método wakeup() del Selector La llamada devuelve un entero que coincide con el número de eventos ocurridos El Selector puede recuperar todas las SelectionKeys de channels con eventos, para ello se utiliza el método siguiente: Set<SelectionKey> selectedKeys() Tema II: Programación con Sockets

89 Ejemplo de uso de un Selector
Selector selector = Selector.open(); ServerSocketChannel sschannel = ServerSocketChannel.open(); sschannel.configureBlocking(false); ServerSocket ssocket = sschannel.socket(); ss.bind(new InetSocketAddress(2345)); sschannel.register(selector, SelectionKey.OP_ACCEPT); //Otros SelectableChannels pueden registrarse en el selector ... int num = selector.select(); //Llamada bloqueante Set<SelectionKey> selectedKeys = selector.selectedKeys() Iterator it = selectedKeys.iterator(); while(it.hasNext()){ SelectionKey key = it.next(); if(key.isAcceptable()){ ServerSocketChannel sschannel = (ServerSocketChannel)key.getChannel(); SocketChannel schannel = sshchannel.accept(); //Llamada no bloqueante } else if (key.isReadable()){ //registrado con SelectionKey.OP_READ } else is (key.isWritable()){ //registrado con SelectionKey.OP_WRITE } Tema II: Programación con Sockets

90 Tema II: Comentarios y referencias
Comentarios y reflexiones Imagina que una aplicación requiere que el tráfico emitido responda a un determinado patrón temporal (VoIP, Video Conferencia, etc). Analiza las ventajas e inconvenientes de usar sockets TCP y sockets UDP en cada caso. ¿Crees que es importante la sincronización de los procesos cuando estos comunican? ¿Qué técnicas de programación habría que utilizar si no contásemos con la sincronización a través de bloqueos? ¿Por qué crees que Java utiliza Streams para realizar entrada/salida en sockets TCP, pero no los utiliza para sockets UDP? ¿Qué es el algoritmo de Nagle y como afecta al funcionamiento de un socket? ¿En qué casos hay que activarlo y en qué casos hay que desactivarlo? Los sockets con entrada/salida asíncrona son más complejos de utilizar y aumentan la complejidad de los programas que los utilizan. ¿Qué ventajas ofrecen a cambio? Referencias M.L. Liu, Computación Distribuida: Fundamentos y Aplicaciones, Pearson Addison Wesley, Capítulo 4 Bruce Eckel, Piensa en Java, Prentice Hall, 2003 Nunca desprecies el poder Wikipedia ( Tema I: Introducción a las computación distribuida Luis López Fernández

91 Tema I: Introducción a las computación distribuida
Tema II: Resumen Contenidos Introducción Concepto de socket Servicios ofrecidos por la API de Sockets Streams Concepto de stream InputStreams y OutPutStreams Readers y Writers Interconexión de streams Sockets TCP La API de stream sockets en Java Sockets TCP y streams Programas de ejemplo con sockets TCP Sockets UDP La API de datagram sockets en Java Entrada/salida en datagram sockets Programas de ejemplo con sockets UDP Sockets con entrada/salida asíncrona en Java El paquete java.nio Buffers Channels Selectors Tema I: Introducción a las computación distribuida Luis López Fernández


Descargar ppt "Tema II: Programación con sockets"

Presentaciones similares


Anuncios Google