Programación de redes en Java

La programación de redes se refiere a la escritura de programas que se ejecutan en múltiples dispositivos (computadoras) que están conectados a través de una red.

El API de J2SE en el paquete java.net contiene clases e interfaces que proporcionan detalles de comunicación de bajo nivel. Puedes usar directamente estas clases e interfaces para concentrarte en resolver problemas, sin prestar atención a los detalles de comunicación.

El paquete java.net proporciona soporte para dos protocolos de red comunes:

  • TCPTCP (del inglés: Transmission Control Protocol, Protocolo de Control de Transmisión) es un protocolo de comunicación de capa de transporte orientado a conexión, confiable y basado en flujo de bytes. La capa TCP se encuentra por encima de la capa IP y por debajo de la capa de aplicación. TCP garantiza una comunicación confiable entre dos aplicaciones. Usualmente se usa en el protocolo de Internet, denominado TCP/IP.

  • UDPUDP (del inglés: User Datagram Protocol, Protocolo de Datagramas de Usuario) se encuentra en la capa de transporte del modelo OSI. Es un protocolo sin conexión. Proporciona datagramas para que las aplicaciones envíen datos entre sí. Debido a que UDP carece de confiabilidad y es un protocolo sin conexión, las aplicaciones normalmente deben tolerar algunas pérdidas, errores o paquetes duplicados.

Este tutorial explica principalmente los siguientes dos temas.

  • Programación de sockets: este es el concepto de red más utilizado y ha sido explicado con gran detalle.

  • Manejo de URL: esta parte se tratará en otra sección. Haz clic aquí para obtener más detalles sobre elmanejo de URL en el lenguaje Java.。


Programación de sockets

Los sockets utilizan TCP para proporcionar un mecanismo de comunicación entre dos computadoras. El programa cliente crea un socket e intenta conectarse al socket del servidor.

Cuando se establece la conexión, el servidor crea un objeto Socket. El cliente y el servidor ahora pueden comunicarse escribiendo y leyendo en el objeto Socket.

La clase java.net.Socket representa un socket, y la clase java.net.ServerSocket proporciona a los programas de servidor un mecanismo para escuchar a los clientes y establecer conexiones con ellos.

Los siguientes pasos ocurren al establecer una conexión TCP entre dos computadoras usando sockets:

  • El servidor instancia un objeto ServerSocket, que representa la comunicación a través de un puerto en el servidor.

  • El servidor llama al método accept() de la clase ServerSocket, que espera hasta que un cliente se conecte al puerto dado en el servidor.

  • Mientras el servidor está esperando, un cliente instancia un objeto Socket, especificando el nombre del servidor y el número de puerto para solicitar la conexión.

  • El constructor de la clase Socket intenta conectar el cliente al servidor y número de puerto especificados. Si se establece la comunicación, se crea un objeto Socket en el cliente que puede comunicarse con el servidor.

  • En el lado del servidor, el método accept() devuelve una nueva referencia de socket en el servidor, que está conectada al socket del cliente.

Una vez establecida la conexión, la comunicación se realiza mediante flujos de E/S. Cada socket tiene un flujo de salida y un flujo de entrada. El flujo de salida del cliente se conecta al flujo de entrada del servidor, y el flujo de entrada del cliente se conecta al flujo de salida del servidor.

TCP es un protocolo de comunicación bidireccional, por lo que los datos pueden enviarse a través de dos flujos de datos al mismo tiempo. A continuación se presentan un conjunto completo de métodos útiles proporcionados por las clases para implementar sockets.


Métodos de la clase ServerSocket

Las aplicaciones de servidor utilizan la clase java.net.ServerSocket para obtener un puerto y escuchar las solicitudes de los clientes.

La clase ServerSocket tiene cuatro constructores:

No. Descripción del método
1 public ServerSocket(int port) throws IOException
Crea un socket de servidor vinculado a un puerto específico.
2 public ServerSocket(int port, int backlog) throws IOException
Crea un socket de servidor con el backlog especificado y lo vincula al número de puerto local especificado.
3 public ServerSocket(int port, int backlog, InetAddress address) throws IOException
Crea un servidor utilizando el puerto especificado, el backlog de escucha y la dirección IP local a la que se va a vincular.
4 public ServerSocket() throws IOException
Crea un socket de servidor no vinculado.

Crea un socket de servidor no vinculado. Si el constructor de ServerSocket no lanza una excepción, significa que tu aplicación se ha vinculado correctamente al puerto especificado y está escuchando las solicitudes de los clientes.

Aquí hay algunos métodos comunes de la clase ServerSocket:

No. Descripción del método
1 public int getLocalPort()
Devuelve el puerto en el que este socket está escuchando.
2 public Socket accept() throws IOException
Escucha y acepta conexiones a este socket.
3 public void setSoTimeout(int timeout)
Habilita/deshabilita SO_TIMEOUT con el valor de tiempo de espera especificado, en milisegundos.
4 public void bind(SocketAddress host, int backlog)
Vincula el ServerSocket a una dirección específica (dirección IP y número de puerto).

Métodos de la clase Socket

La clase java.net.Socket representa el socket que tanto el cliente como el servidor utilizan para comunicarse entre sí. El cliente obtiene un objeto Socket mediante la instanciación, mientras que el servidor obtiene un objeto Socket a través del valor de retorno del método accept().

La clase Socket tiene cinco constructores.

No. Descripción del método
1 public Socket(String host, int port) throws UnknownHostException, IOException.
Crea un socket de flujo y lo conecta al número de puerto especificado en el host especificado.
2 public Socket(InetAddress host, int port) throws IOException
Crea un socket de flujo y lo conecta al número de puerto especificado en la dirección IP especificada.
3 public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.
Crea un socket y lo conecta al puerto remoto especificado en el host remoto especificado.
4 public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.
Crea un socket y lo conecta al puerto remoto especificado en la dirección remota especificada.
5 public Socket()
Crea un socket no conectado mediante el SocketImpl de tipo predeterminado del sistema.

Cuando el constructor de Socket regresa, no se ha limitado a instanciar un objeto Socket; en realidad intenta conectarse al servidor y al puerto especificados.

A continuación se enumeran algunos métodos de interés. Ten en cuenta que tanto el cliente como el servidor tienen un objeto Socket, por lo que tanto el cliente como el servidor pueden llamar a estos métodos.

No. Descripción del método
1 public void connect(SocketAddress host, int timeout) throws IOException
Conecta este socket al servidor y especifica un valor de tiempo de espera.
2 public InetAddress getInetAddress()
Devuelve la dirección a la que está conectado el socket.
3 public int getPort()
Devuelve el puerto remoto al que está conectado este socket.
4 public int getLocalPort()
Devuelve el puerto local al que está vinculado este socket.
5 public SocketAddress getRemoteSocketAddress()
Devuelve la dirección del extremo al que está conectado este socket, o null si no está conectado.
6 public InputStream getInputStream() throws IOException
Devuelve el flujo de entrada de este socket.
7 public OutputStream getOutputStream() throws IOException
Devuelve el flujo de salida de este socket.
8 public void close() throws IOException
Cierra este socket.

Métodos de la clase InetAddress

Esta clase representa una dirección de Protocolo de Internet (IP). A continuación se enumeran los métodos más útiles para la programación de sockets:

No. Descripción del método
1 static InetAddress getByAddress(byte[] addr)
Devuelve un objeto InetAddress dada una dirección IP sin procesar.
2 static InetAddress getByAddress(String host, byte[] addr)
Crea un InetAddress según el nombre de host y la dirección IP proporcionados.
3 static InetAddress getByName(String host)
Determina la dirección IP del host dado el nombre de host.
4 String getHostAddress() 
Devuelve la cadena de la dirección IP (en forma de texto).
5 String getHostName() 
Obtiene el nombre de host de esta dirección IP.
6 static InetAddress getLocalHost()
Devuelve el host local.
7 String toString()
Convierte esta dirección IP en una cadena (String).

Ejemplo de cliente Socket

El siguiente GreetingClient es un programa cliente que se conecta al servidor a través de un socket, envía una solicitud y luego espera una respuesta.

Código del archivo GreetingClient.java:

//Nombre del archivo GreetingClient.java import java.net.*; import java.io.*; public class GreetingClient { public static void main(String [] args) { String serverName = args[0]; int port = Integer.parseInt(args[1]); try { System.out.println("Conectando al host:" + serverName + ", número de puerto:" + port); Socket client = new Socket(serverName, port); System.out.println("Dirección del host remoto:" + client.getRemoteSocketAddress()); OutputStream outToServer = client.getOutputStream(); DataOutputStream out = new DataOutputStream(outToServer); out.writeUTF("Hello from " + client.getLocalSocketAddress()); InputStream inFromServer = client.getInputStream(); DataInputStream in = new DataInputStream(inFromServer); System.out.println("Respuesta del servidor:" + in.readUTF()); client.close(); }catch(IOException e) { e.printStackTrace(); } } }

Ejemplo de servidor Socket

El siguiente programa GreetingServer es una aplicación de servidor que utiliza un Socket para escuchar un puerto específico.

Código del archivo GreetingServer.java:

//Nombre del archivo GreetingServer.java import java.net.*; import java.io.*; public class GreetingServer extends Thread { private ServerSocket serverSocket; public GreetingServer(int port) throws IOException { serverSocket = new ServerSocket(port); serverSocket.setSoTimeout(10000); } public void run() { while(true) { try { System.out.println("Esperando conexión remota, número de puerto:" + serverSocket.getLocalPort() + "..."); Socket server = serverSocket.accept(); System.out.println("Dirección del host remoto:" + server.getRemoteSocketAddress()); DataInputStream in = new DataInputStream(server.getInputStream()); System.out.println(in.readUTF()); DataOutputStream out = new DataOutputStream(server.getOutputStream()); out.writeUTF("Gracias por conectarte a mí:" + server.getLocalSocketAddress() + "\nGoodbye!"); server.close(); }catch(SocketTimeoutException s) { System.out.println("Socket timed out!"); break; }catch(IOException e) { e.printStackTrace(); break; } } } public static void main(String [] args) { int port = Integer.parseInt(args[0]); try { Thread t = new GreetingServer(port); t.run(); }catch(IOException e) { e.printStackTrace(); } } }

Compila el código de los dos archivos Java anteriores y ejecuta el siguiente comando para iniciar el servicio, usando el número de puerto 6066:

$ javac GreetingServer.java 
$ java GreetingServer 6066
等待远程连接,端口号为:6066...

Abre una nueva ventana de comandos y ejecuta el comando anterior para iniciar el cliente:

$ javac GreetingClient.java 
$ java GreetingClient localhost 6066
连接到主机:localhost ,端口号:6066
远程主机地址:localhost/127.0.0.1:6066
服务器响应: 谢谢连接我:/127.0.0.1:6066
Goodbye!
Otras extensiones