Introducción a la programación de redes en Java
Una visión general de las API de red de Java en java.net y java.net.http para conectarse a servicios remotos.
Introducción a la programación de redes en Java
La programación de redes es cómo un programa Java habla con otro programa — al otro lado de la sala o al otro lado del mundo. El JDK incluye para ello una pila completa, con todo incorporado, en dos paquetes: el veterano java.net (URLs, sockets, direcciones) y el moderno java.net.http (el HttpClient introducido en Java 11). Esta parte del libro recorre esa pila desde las comodidades de alto nivel hasta los sockets en bruto.
Las capas, de alta a baja
Las API de red de Java forman una escalera. Elija el peldaño más alto que haga el trabajo:
| Peldaño | API | Úsela para |
|---|---|---|
| El más alto | HttpClient (java.net.http) | HTTP/HTTPS moderno: llamadas REST, descargas, asíncrono |
URL / URLConnection / HttpURLConnection | HTTP heredado y otros protocolos de URL | |
Socket / ServerSocket | Protocolos TCP personalizados, su propio cliente/servidor | |
| El más bajo | DatagramSocket | Mensajería UDP sin conexión |
| Apoyo | InetAddress | Resolución y representación de direcciones IP |
La regla general: si está llamando a una API HTTP, recurra a HttpClient. Baje a los sockets solo cuando hable un protocolo distinto de HTTP o construya un servidor propio.
TCP vs. UDP
Dos protocolos de transporte subyacen a casi todo:
- TCP (
Socket,ServerSocket) es una conexión: fiable, ordenada, basada en flujo. Los bytes que escribe llegan intactos y en orden, o recibe un error. HTTP, las bases de datos y la mayoría de los protocolos de aplicación viajan sobre TCP. - UDP (
DatagramSocket) es sin conexión: usted dispara paquetes independientes («datagramas») sin apretón de manos, sin orden y sin garantía de entrega. Cambia la fiabilidad por baja latencia — usado para DNS, transmisión de vídeo y juegos.
Cliente vs. servidor
Un cliente inicia una conexión hacia una dirección y un puerto conocidos. Un servidor se enlaza a un puerto y espera para aceptar conexiones entrantes. La misma clase Socket representa la conexión activa en ambos extremos; la asimetría está solo en quién inicia la conversación. Los capítulos posteriores construyen ambos lados.
Bloqueantes por defecto
Las API clásicas de java.net son bloqueantes: socket.getInputStream().read() aparca el hilo que llama hasta que llegan datos, y serverSocket.accept() aparca hasta que un cliente se conecta. Es sencillo de razonar pero significa un hilo por conexión. (Los canales de java.nio y los hilos virtuales abordan la escalabilidad; esta parte se queda en las API bloqueantes, que son el punto de partida correcto.)
Un ejemplo trabajado: toda la pila en un solo archivo
Para hacer las piezas concretas, este programa arranca un servidor HTTP diminuto en la interfaz de bucle invertido, y luego lo llama con el moderno HttpClient — un viaje de ida y vuelta cliente/servidor completo en una sola JVM, sin necesidad de una red externa.
Qué llevarse de la ejecución:
- Un cliente y un servidor funcionales caben en un archivo corto. Las aplicaciones reales los reparten entre máquinas, pero la API es idéntica —
HttpServeraceptó una conexión yHttpClientabrió una, encontrándose sobre TCP en la interfaz de bucle invertido (127.0.0.1). Esta es la forma de todo programa en red: un lado espera, un lado llama. - Enlazar al puerto 0 dejó que el sistema operativo eligiera un puerto libre, que
server.getAddress().getPort()informó de vuelta. Codificar un puerto a mano arriesga «address already in use»; el puerto 0 es el truco estándar para pruebas y demos que solo necesitan un puerto. - El cliente nunca tocó un socket directamente.
HttpClientmanejó la conexión, la línea de solicitud HTTP, las cabeceras y el análisis de la respuesta — ese es el valor de subir al peldaño más alto de la escalera. Los capítulos de sockets, más adelante, muestran lo que ocultó. - La respuesta llevaba metadatos estructurados: un
statusCode()(200), unbody()y unaversion(). Las respuestas HTTP son más que texto; el cliente las modeló como un objetoHttpResponsetipado, de modo que usted lee campos en lugar de analizar un flujo. server.stop(0)liberó el puerto. Los recursos de red — sockets, puertos de servidor, conexiones — son escasos handles del sistema operativo; cada capítulo de esta parte los cierra explícitamente (o con try-with-resources) para que no se filtren.
Qué cubre el resto de esta parte
URL y sus clases de conexión, el moderno HttpClient en profundidad, TCP en bruto con Socket y ServerSocket, UDP sin conexión con DatagramSocket, y la resolución de direcciones con InetAddress. El siguiente capítulo empieza por el objeto de red más familiar de todos: la URL.
Práctica
Está escribiendo un servicio Java que llama a una API REST de terceros sobre HTTPS y necesita solicitudes tanto síncronas como asíncronas en un JDK moderno. ¿Qué API es la primera opción más apropiada?