La API de Java Socket existe desde hace más de dos décadas. Se ha mantenido y actualizado durante ese período, pero incluso el código mejor conservado finalmente debe actualizarse para mantenerse al día con las tecnologías contemporáneas. Las clases fundamentales que manejan la interacción de Socket en Java 13 se han vuelto a implementar para aprovechar el estado actual de Java mientras se preparan para desarrollos futuros.
¿Qué es la API de socket y cómo funciona?
Los objetos en la API de socket de Java (java.net.ServerSocket y java.net.Socket) le brindan control directo sobre los sockets que un servidor escucha y los sockets que entregan datos.
ServerSocket se puede usar para esperar requests de conexión en un puerto y, si se acepta, devolver un objeto Socket que se puede usar para leer y escribir datos. Ambas clases emplean una implementación basada en SOCKS, y el trabajo duro lo realiza una implementación interna de SocketImpl. Este código es fácil de aprender y usar, pero existe desde Java 1.0, como se ve por su antigüedad. Esta combinación de código Java y C más antiguo ha requerido aumentos en el tamaño predeterminado de la pila de subprocesos desde su inicio, así como la aparición de dificultades de estabilidad y concurrencia a lo largo del tiempo. Hemos llegado a una etapa en la que la única opción viable es una reconstrucción completa.
Implementar la API de socket heredada
Este JEP propone reemplazar la implementación de SocketImpl con una nueva implementación de NioSocketImpl. Esta solución utiliza la misma arquitectura que la implementación NIO (Nueva E/S) y se conecta con los métodos de caché de búfer actuales, lo que elimina la necesidad de una pila de subprocesos. Con estas modificaciones se incluyen varias modificaciones beneficiosas adicionales, como java.lang.ref. En caso de que la implementación de SocketImpl se recolecte como basura en los sockets que no se han cerrado y se produzcan acciones de tiempo de espera con el Socket en modo sin bloqueo cuando se sondea, se utilizará un enfoque más limpio para cerrar los sockets.
Se ha creado una propiedad del sistema para utilizar la implementación original con el fin de reducir la posibilidad de dificultades al volver a implementar técnicas que han estado en uso durante más de 20 años.
Se usará la implementación anterior si se establece usePlainSocketImpl=true .
Cabe señalar que SocketImpl es una técnica SPI histórica que no se especificó en el pasado; la versión actual se esfuerza por simular un comportamiento indefinido cuando es posible. Sin embargo, hay algunas situaciones extremas que pueden fallar al utilizar la nueva implementación, que se pueden ver aquí. Todos menos dos de estos pueden solucionarse utilizando el atributo del sistema mencionado anteriormente. La implementación anterior de FileInputStream y FileOutputStream devolvía flujos de entrada y salida, que se usaban para expandirlos. Este no es el caso con la implementación actual.
Las conexiones que devuelven Sockets con el otro tipo (personalizado o de plataforma) de SocketImpl no pueden ser aceptadas por ServerSockets que usan un SocketImpl personalizado o de plataforma.
Entonces, ¿cuáles son las ventajas de esto?
La implementación anterior fue difícil de mantener y mejorar; sin embargo, la API de Java Socket será más fácil de mantener ahora que se han realizado estas mejoras. La confiabilidad del código de socket debería mejorar como resultado de un mejor mantenimiento. La implementación de NIO también se realiza en un nivel inferior, lo que permite que las clases Socket y ServerSocket permanezcan igual.
Estas modificaciones no solo facilitan el mantenimiento de este código, sino que también hacen que la implementación esté preparada para el futuro. Un proyecto denominado Project Loom se está ejecutando actualmente en el JDK. Este proyecto introduce la noción de fibras, que es una forma novedosa de ver los hilos (obtenga más información en nuestro artículo anterior de Project Loom). Cuando se publique Project Loom, la implementación de NIO podrá aprovecharlo, mientras que la implementación anterior no será adecuada para su propósito. Debido a que la implementación de NIO utiliza bloqueos java.util.concurrent en lugar de métodos sincronizados, esto es concebible.
Esta salida de depuración se puede ver ejecutando una clase que instancia Socket y ServerSocket. Así es como se ve el valor predeterminado (nuevo):
Java
java -XX:+TraceClassLoading JEP353 | grep Socket [0.033s][info ][class,load] java.net.Socket source: jrt:/java.base [0.035s][info ][class,load] java.net.SocketOptions source: jrt:/java.base [0.035s][info ][class,load] java.net.SocketImpl source: jrt:/java.base [0.039s][info ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800b50840 source: java.net.SocketImpl [0.042s][info ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base [0.042s][info ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base [0.043s][info ][class,load] sun.nio.ch.SocketDispatcher source: jrt:/java.base [0.044s][info ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base [0.044s][info ][class,load] java.net.SocksSocketImpl source: jrt:/java.base [0.044s][info ][class,load] java.net.ServerSocket source: jrt:/java.base [0.045s][info ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base [0.045s][info ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
Uso de las expresiones Switch para el socket
Ejemplo 1
Java
System.out.println(switch (args[0]) { // a simple switch case case "1" -> 1; case "2" -> 2; default -> args[0].length(); });
Producción:
//This Switch case prints accordingly //User entered 1 ->1
Ejemplo #2
Java
System.out.println(switch (args[0]) { case "1": yield 1; case "2": yield 2; default: { int len = args[0].length(); yield len; } });
Producción:
//This Switch case prints accordingly //User entered 1 -> yield 1
Publicación traducida automáticamente
Artículo escrito por therebootedcoder y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA