Clase Socket en Java
En Java, la clase Socket de java.net proporciona un mecanismo de
comunicación entre dos computadoras utilizando el protocolo TCP.
Un socket permite que un cliente y un servidor se conecten y
puedan intercambiar datos mediante flujos de entrada y salida.
Este artículo explorará los constructores y métodos principales de la
clase Socket, con ejemplos prácticos que muestran cómo establecer
conexiones entre un cliente y un servidor.
¿Qué es un Socket?
Un socket es un punto final de la comunicación entre dos
computadoras en una red. Permite a un programa cliente establecer
una conexión con un servidor a través de un puerto específico. Una
vez que la conexión se establece, ambos pueden comunicarse
utilizando flujos de entrada y salida.
El cliente crea un socket y se conecta al servidor.
El servidor escucha conexiones entrantes usando un
objeto ServerSocket.
Diagrama del Proceso:
1. El cliente crea un socket y se conecta al servidor.
2. El servidor acepta la conexión y crea un socket para
comunicarse con el cliente.
3. Ambos extremos intercambian datos
utilizando InputStream y OutputStream.
Declaración de la Clase Socket
public class Socket extends Object implements Closeable
Constructores de la Clase Socket
La clase Socket ofrece varios constructores para crear sockets de
diferentes maneras:
1. Socket(): Crea un socket no conectado. Debes conectarlo
manualmente utilizando el método connect().
2. Socket(String host, int port): Crea un socket e intenta
conectarse al servidor especificado por el nombre de host y el
número de puerto.
3. Socket(InetAddress host, int port): Igual que el anterior,
pero utiliza un objeto InetAddress para especificar la dirección
IP en lugar de un nombre de host.
4. Socket(Proxy proxy): Crea un socket no conectado que
utiliza un proxy específico para las conexiones.
5. Socket(String host, int port, InetAddress localAddr, int
localPort): Crea un socket y se conecta al servidor
especificado por el host y el puerto, vinculado a una dirección
y puerto locales.
6. Socket(InetAddress address, int port, InetAddress
localAddr, int localPort): Similar al anterior, pero en lugar de
un nombre de host utiliza un objeto InetAddress para
especificar la dirección del servidor.
7. Socket(String host, int port, boolean stream): Crea un
socket con un tipo de flujo (stream) o de datagramas
dependiendo del valor booleano pasado. Este constructor está
en desuso.
8. Socket(InetAddress host, int port, boolean stream):
Similar al anterior, pero usa un objeto InetAddress en lugar de
un nombre de host. Este constructor también está en desuso.
Estos son los principales constructores que puedes usar para
instanciar un objeto Socket. La mayoría de las aplicaciones utilizan
los constructores básicos, pero para situaciones más específicas, los
otros constructores permiten definir con mayor detalle cómo se
establece la conexión.
Ejemplo: Crear un Socket y Conectarse a un Servidor
import java.net.*;
import java.io.*;
public class ClienteSocket {
public static void main(String[] args) {
try {
// Conectar al servidor en el host y puerto especificados
Socket cliente = new Socket("localhost", 6066);
System.out.println("Conectado a " +
cliente.getRemoteSocketAddress());
// Obtener el flujo de salida para enviar datos al servidor
OutputStream salida = cliente.getOutputStream();
DataOutputStream dos = new DataOutputStream(salida);
dos.writeUTF("Hola desde " + cliente.getLocalSocketAddress());
// Obtener el flujo de entrada para leer la respuesta del servidor
InputStream entrada = cliente.getInputStream();
DataInputStream dis = new DataInputStream(entrada);
System.out.println("El servidor dice: " + dis.readUTF());
// Cerrar el socket
cliente.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explicación:
Este ejemplo muestra cómo un cliente se conecta a un servidor
en el puerto 6066, envía un mensaje, recibe una respuesta y
cierra la conexión.
Métodos Principales de la Clase Socket
1. bind(SocketAddress bindpoint): Asocia el socket a una
dirección local específica.
2. close(): Cierra el socket.
3. connect(SocketAddress endpoint, int timeout): Conecta
el socket al servidor con un tiempo de espera específico.
4. getInetAddress(): Devuelve la dirección a la que el socket
está conectado.
5. getInputStream(): Devuelve el flujo de entrada del socket.
6. getOutputStream(): Devuelve el flujo de salida del socket.
7. getPort(): Devuelve el número de puerto al que está
conectado el socket.
8. isConnected(): Verifica si el socket está conectado.
9. setSoTimeout(int timeout): Establece el tiempo de espera
para las operaciones de lectura en el socket.
10. getLocalAddress(): Devuelve la dirección IP local a la
que está vinculado el socket.
11. getLocalPort(): Devuelve el número de puerto local al
que está vinculado el socket.
12. getSoLinger(): Obtiene el tiempo de «linger» (espera
para cerrar el socket).
13. setSoLinger(boolean on, int linger):
Habilita/deshabilita el tiempo de linger y establece su duración.
14. getReceiveBufferSize(): Devuelve el tamaño del búfer
de recepción.
15. setReceiveBufferSize(int size): Establece el tamaño
del búfer de recepción.
16. getSendBufferSize(): Devuelve el tamaño del búfer de
envío.
17. setSendBufferSize(int size): Establece el tamaño del
búfer de envío.
18. getTcpNoDelay(): Verifica si la opción TCP_NODELAY
está habilitada (si se desactiva el algoritmo de Nagle).
19. setTcpNoDelay(boolean on): Habilita/deshabilita la
opción TCP_NODELAY.
20. isClosed(): Verifica si el socket está cerrado.
21. isBound(): Verifica si el socket está vinculado a una
dirección local.
22. getKeepAlive(): Verifica si el socket está usando la
opción de «keep-alive».
23. setKeepAlive(boolean on): Habilita/deshabilita la
opción de «keep-alive».
24. getReuseAddress(): Verifica si se permite reutilizar la
dirección local.
25. setReuseAddress(boolean on): Habilita/deshabilita la
opción de reutilización de direcciones.
26. getOOBInline(): Verifica si el socket está configurado
para recibir datos fuera de banda en línea.
27. setOOBInline(boolean on): Habilita/deshabilita la
recepción de datos fuera de banda en línea.
28. sendUrgentData(int data): Envía datos urgentes fuera
de banda.
29. getChannel(): Devuelve el canal asociado al socket (si
existe).
30. shutdownInput(): Desactiva el canal de entrada del
socket.
31. shutdownOutput(): Desactiva el canal de salida del
socket.
32. getTrafficClass(): Devuelve la clase de tráfico o la
precedencia de los paquetes enviados.
33. setTrafficClass(int tc): Establece la clase de tráfico o
precedencia para los paquetes enviados.
Ejemplo: Conectar con Tiempo de Espera
import java.net.*;
import java.io.*;
public class ClienteConTimeout {
public static void main(String[] args) {
try {
Socket cliente = new Socket();
cliente.connect(new InetSocketAddress("localhost", 6066), 5000); //
Tiempo de espera de 5 segundos
System.out.println("Conectado a " +
cliente.getRemoteSocketAddress());
OutputStream salida = cliente.getOutputStream();
DataOutputStream dos = new DataOutputStream(salida);
dos.writeUTF("Mensaje con timeout");
InputStream entrada = cliente.getInputStream();
DataInputStream dis = new DataInputStream(entrada);
System.out.println("El servidor dice: " + dis.readUTF());
cliente.close();
} catch (SocketTimeoutException e) {
System.out.println("La conexión ha superado el tiempo de espera.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explicación:
En este ejemplo, el cliente intenta conectarse al servidor con
un tiempo de espera de 5 segundos. Si no se puede conectar
dentro de ese tiempo, se lanza una
excepción SocketTimeoutException.
Ejemplo Completo de Comunicación Cliente-
Servidor
El siguiente ejemplo muestra una aplicación completa donde un
servidor escucha conexiones de los clientes y responde a cada uno
de ellos.
Ejemplo: Servidor
import java.net.*;
import java.io.*;
public class ServidorSocket extends Thread {
private ServerSocket servidorSocket;
public ServidorSocket(int puerto) throws IOException {
servidorSocket = new ServerSocket(puerto);
}
public void run() {
while(true) {
try {
System.out.println("Esperando a que un cliente se conecte...");
Socket servidor = servidorSocket.accept();
System.out.println("Conectado a " +
servidor.getRemoteSocketAddress());
// Leer datos del cliente
DataInputStream entrada = new
DataInputStream(servidor.getInputStream());
System.out.println("Mensaje del cliente: " + entrada.readUTF());
// Enviar respuesta al cliente
DataOutputStream salida = new
DataOutputStream(servidor.getOutputStream());
salida.writeUTF("Gracias por conectarte a " +
servidor.getLocalSocketAddress());
servidor.close();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
int puerto = 6066;
try {
Thread t = new ServidorSocket(puerto);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explicación:
Este servidor espera conexiones de clientes en el puerto 6066,
lee un mensaje de cada cliente y envía una respuesta antes de
cerrar la conexión.
Ejemplo: Cliente
import java.net.*;
import java.io.*;
public class ClienteSocketSimple {
public static void main(String[] args) {
try {
Socket cliente = new Socket("localhost", 6066);
System.out.println("Conectado al servidor");
DataOutputStream salida = new
DataOutputStream(cliente.getOutputStream());
salida.writeUTF("Hola servidor");
DataInputStream entrada = new
DataInputStream(cliente.getInputStream());
System.out.println("Respuesta del servidor: " + entrada.readUTF());
cliente.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explicación:
El cliente se conecta al servidor, envía un mensaje y espera la
respuesta. Una vez recibida, se cierra la conexión.
Conclusión
La clase Socket en Java es esencial para crear aplicaciones que se
comunican a través de la red utilizando el protocolo TCP. Con los
métodos y ejemplos proporcionados, puedes establecer conexiones
entre clientes y servidores, enviar y recibir datos, y manejar
configuraciones avanzadas como el tiempo de espera.