Sockets en Java (UDP y TCP)

| 2013-09-12 | 2 Comentarios »

Sockets

Designa un concepto abstracto por el cual dos programas (posiblemente situados en computadoras distintas) pueden intercambiar cualquier flujo de datos, generalmente de manera fiable y ordenada.

Los sockets de Internet constituyen el mecanismo para la entrega de paquetes de datos provenientes de la tarjeta de red a los procesos o hilos apropiados. Un socket queda definido por un par de direcciones IP local y remota, un protocolo de transporte y un par de números de puerto local y remoto.

Protocolos de Transporte

« UDP (User Datagram Protocol): Es un protocolo no orientado a conexión. Es decir cuando una maquina A envía paquetes a una maquina B, el flujo es unidireccional. La transferencia de datos es realizada sin haber realizado previamente una conexión con la máquina de destino (maquina B), y el destinatario recibirá los datos sin enviar una confirmación al emisor (la maquina A). Esto es debido a que la encapsulación de datos enviada por el protocolo UDP no permite transmitir la información relacionada al emisor. Por ello el destinatario no conocerá al emisor de los datos excepto su IP.

« TCP (Transmission Control Protocol): Contrariamente a UDP, el protocolo TCP está orientado a conexión. Cuando una máquina A envía datos a una máquina B, la máquina B es informada de la llegada de datos, y confirma su buena recepción. Aquí interviene el control CRC de datos que se basa en una ecuación matemática que permite verificar la integridad de los datos transmitidos. De este modo, si los datos recibidos son corruptos, el protocolo TCP permite que los destinatarios soliciten al emisor que vuelvan a enviar los datos corruptos.

Socket TCP

Basicamente, este es el funcionamiento de los Socket que necesitamos para una conexión TCP. En el que podemos distinguir dos tipos de Socket el del Servidor y el del Cliente.

La creación del socket en el servidor se remite a crear el socket, indicar por que puerto se harán las escuchas y esperar a la llamada de un cliente para aceptar la conexión, en cambio un cliente creará el socket e indicará donde se encuentra y por que puerto quiere conectarse, de está forma Cliente y Servidor crearán una conexión.

Servidor:
Para crear los socket se crea un objeto del tipo ServerSocket, este método pertenece a la clase java.net.Serversocket

Una vez que hemos creado el objeto socket mandamos un parámetro que indicará el puerto por el que se realzará las comunicaciones.

Para realizar una conexión entre Cliente-Servidor, el servidor usará el método socket.accept para confirmar que se ha iniciado la conexión.

Cliente:
Primero crea un objeto del tipo Socket que pertenece a la clase java.net.Serversocket, Después se obtiene un objeto InetAddress, y usando el método getByName le indicamos donde se va a ejecutar el cliente, en nuestro caso indicamos que será en localhost.

Finalmente creamos un objeto de tipo socket al que pasaremos la dirección donde se está ejecutando el cliente, y el puerto por donde se conectará al servidor.

Ejemplo TCP: El servidor esperará a un cliente y mostrará todos los mensajes que el cliente le envíe. El cliente solo mandará mensajes al servidor, y al escribir la palabra “fin” terminarán ambos programas.

– Servidor TCP:


import java.net.*;
//importar la libreria java.net

import java.io.*;
//importar la libreria java.io

// declaramos la clase servidortcp

public class servidortcp {

// método principal main de la clase
 public static void main(String argv[]) {

// declaramos un objeto ServerSocket para realizar la comunicación
 ServerSocket socket;
// creamos una varible boolean con el valor a false
 boolean fin = false;

// Declaramos un bloque try y catch para controlar la ejecución del subprograma
 try {

// Instanciamos un ServerSocket con la dirección del destino y el
// puerto que vamos a utilizar para la comunicación

 socket = new ServerSocket(6000);

// Creamos un socket_cli al que le pasamos el contenido del objeto socket después
// de ejecutar la función accept que nos permitirá aceptar conexiones de clientes
 Socket socket_cli = socket.accept();

// Declaramos e instanciamos el objeto DataInputStream
// que nos valdrá para recibir datos del cliente

 DataInputStream in =
 new DataInputStream(socket_cli.getInputStream());

// Creamos un bucle do while en el que recogemos el mensaje
// que nos ha enviado el cliente y después lo mostramos
// por consola

 do {
 String mensaje ="";
 mensaje = in.readUTF();
 System.out.println(mensaje);
 } while (1>0);
 }
// utilizamos el catch para capturar los errores que puedan surgir
 catch (Exception e) {

// si existen errores los mostrará en la consola y después saldrá del
// programa
 System.err.println(e.getMessage());
 System.exit(1);
 }
 }
}

– Cliente TCP:


import java.net.*;
// importar la libreria java.net
import java.io.*;
// importar la libreria java.io

// declararamos la clase clientetcp
public class clientetcp {

// método principal de la clase
 public static void main(String argv[]) {

// Creamos una instancia BuffererReader en la
// que guardamos los datos introducido por el usuario

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

// declaramos un objeto socket para realizar la comunicación
 Socket socket;

// declaramos e instanciamos un objeto de tipo byte
 byte[] mensaje_bytes = new byte[256];

// declaramos una variable de tipo string
 String mensaje="";

// Declaramos un bloque try y catch para controlar la ejecución del subprograma
 try {

// Instanciamos un socket con la dirección del destino y el
// puerto que vamos a utilizar para la comunicación
 socket = new Socket("127.0.0.1",6000);

// Declaramos e instanciamos el objeto DataOutputStream
// que nos valdrá para enviar datos al servidor destino
 DataOutputStream out =
 new DataOutputStream(socket.getOutputStream());

// Creamos un bucle do while en el que enviamos al servidor el mensaje
// los datos que hemos obtenido despues de ejecutar la función
// "readLine" en la instancia "in"

 do {
 mensaje = in.readLine();
// enviamos el mensaje codificado en UTF
 out.writeUTF(mensaje);
// mientras el mensaje no encuentre la cadena fin, seguiremos ejecutando
// el bucle do-while
 } while (!mensaje.startsWith("fin"));
 }
// utilizamos el catch para capturar los errores que puedan surgir
 catch (Exception e) {
// si existen errores los mostrará en la consola y después saldrá del
// programa
 System.err.println(e.getMessage());
 System.exit(1);
 }
 }
}

Socket UDP:

En este ejemplo vemos que cada paquete de datos podrá tansportar un máximo de 256 bytes por paquete, que es el tamaño máximo que se intercambia el servidor y el cliente.

Además, cuando queremos enviar datos, especificamos el buffer de los datos que queremos enviar, en nuestro caso 256, la longitud máxima de datos, la dirección y el puerto de destino del datagrama. La dirección destino se especifica con el objeto InetAddress, mientras que el puerto es un número entero (6000). El código esta bastante comentado y tiene bastantes explicaciones que pueden ayudaros.

Comentando un poco el código, podemos ver que el cliente para enviar datos usará el método send() de la clase DatagremSocket.

Por otro lado el servidor para recibir datos lo que hace es crear un DatagramSocket para recibir paquetes especificando el número de puerto en el constructor. De esta forma, el servidor estará esperando por el puerto especificado cualquier paquete entrante.

Ejemplo UDP: El servidor esperará a un cliente y mostrará respuesta si se le envía “hola” o “fin”. El cliente solo mandará mensajes al servidor, y al escribir la palabra “fin” terminará su ejecución.

– Servidor UDP:


import java.net.*;
import java.io.*;
public class servidorudp {
 public static void main(String argv[]) {

DatagramSocket socket;
 boolean fin = false;

try {
 //Creamos el socket
 socket = new DatagramSocket(6000);

byte[] mensaje_bytes = new byte[256];
 String mensaje ="";
 mensaje = new String(mensaje_bytes);
 String mensajeComp ="";

DatagramPacket paquete = new DatagramPacket(mensaje_bytes,256);
 DatagramPacket envpaquete = new DatagramPacket(mensaje_bytes,256);

int puerto;
 InetAddress address;
 byte[] mensaje2_bytes = new byte[256];

//Iniciamos el bucle
 do {
 // Recibimos el paquete
 socket.receive(paquete);
 // Lo formateamos
 mensaje = new String(mensaje_bytes).trim();
 // Lo mostramos por pantalla
 System.out.println(mensaje);
 //Obtenemos IP Y PUERTO
 puerto = paquete.getPort();
 address = paquete.getAddress();

 if (mensaje.startsWith("fin")) {
 mensajeComp="chauuuuuuu cliente";
 }

 if (mensaje.startsWith("hola")) {
 mensajeComp="hola cliente";
 }

 //formateamos el mensaje de salida
 mensaje2_bytes = mensajeComp.getBytes();

//Preparamos el paquete que queremos enviar
 envpaquete = new DatagramPacket(mensaje2_bytes,mensajeComp.length(),address,puerto);

// realizamos el envio
 socket.send(envpaquete);

} while (1>0);
 }
 catch (Exception e) {
 System.err.println(e.getMessage());
 System.exit(1);
 }
 }
}

– Cliente UDP:


import java.net.*;
import java.io.*;

//declaramos la clase udp
public class clienteudp {
 public static void main(String argv[]) {

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

//Definimos el sockets, número de bytes del buffer, y mensaje.
 DatagramSocket socket;
 InetAddress address;
 byte[] mensaje_bytes = new byte[256];
 String mensaje="";
 mensaje_bytes=mensaje.getBytes();

//Paquete
 DatagramPacket paquete;

 String cadenaMensaje="";

DatagramPacket servPaquete;

byte[] RecogerServidor_bytes = new byte[256];

 try {
 socket = new DatagramSocket();

address=InetAddress.getByName("localhost");

do {
 mensaje = in.readLine();
 mensaje_bytes = mensaje.getBytes();
 paquete = new DatagramPacket(mensaje_bytes,mensaje.length(),address,6000);
 socket.send(paquete);

RecogerServidor_bytes = new byte[256];

//Esperamos a recibir un paquete
 servPaquete = new DatagramPacket(RecogerServidor_bytes,256);
 socket.receive(servPaquete);

//Convertimos el mensaje recibido en un string
 cadenaMensaje = new String(RecogerServidor_bytes).trim();

//Imprimimos el paquete recibido
 System.out.println(cadenaMensaje);
 } while (!mensaje.startsWith("fin"));
 }
 catch (Exception e) {
 System.err.println(e.getMessage());
 System.exit(1);
 }
 }
}

Acerca del autor: Rodrigo Paszniuk

Ingeniero Informático, amante de la tecnología, la música, el ciclismo y aprender cosas nuevas.

Posts Relacionados

  • Electron, framework Javascript para crear aplicaciones de escritorio
  • JSF 2 con Maven – Hola Mundo
  • Java RMI
  • Gestión de cambios de la base de datos – Liquibase



SEGUÍNOS EN FACEBOOK


GITHUB