COMUNICACIONES

APARTADOS

Sockets
InetAddress
Arquitectura Cliente-Servidor
Soportar conexiones múltiples(Hilos)

Sockets

Un socket es el punto final de comunicación entre dos puntos.

Los sockets se usarán para el proceso de intercambio de datos entre dos procesos. La información transmitida se manipulará de forma muy similar a como la realiza un archivo.

Los dos tipos de sockets que nos encontraremos serán los "streams" y los "datagramas".

Datagramas (UDP, User Datagram Protocol). Servicio de envío sin conexión. Cada mensaje es envíada de una máquina a otra basándose únicamente en la información contenida en el propio datagrama. Cuando se envían varios datagramas pueden "tomar caminos distintos" y llegar en "cualquier orden".

Streams (TCP, Transport Control Protocol). Servicio orientado a la conexión. Se establece primero la conexión y luego se envían los paquetes.

InetAddress

A continuación se va a ver un ejemplo de uso de la clase InetAddress

import java.net.*;

public class comunicaciones1
{

  public static void main(String args[]) throws UnknownHostException
{

byte []direccionIP;
InetAddress maquina;
String nombreMaquina;
    //Primero hay que obtener una referencia a la máquina local mediante el método estático
//public static InetAddress getLocalHost()

maquina = InetAddress.getLocalHost();

//Se va a usar el siguiente método:
//public byte[] getAddress().
//Este método devolverá la dirección IP en grupos de 4 bytes

direccionIP = maquina.getAddress();
System.out.println("DIRECCION IP:" + direccionIP[0] + "."
+ direccionIP[1] + "." + direccionIP[2] + "." + direccionIP[3]);

nombreMaquina = maquina.getHostName();
System.out.println("NOMBRE HOST: " + nombreMaquina);

nombreMaquina = maquina.getHostAddress();
//En la anterior sentencia se obtiene la dirección IP de la máquina de forma textual, es decir,
//en una cadena y separada por puntos

System.out.println("DIRECCION MAQUINA " + nombreMaquina);

  }  
}    

Haz clic aquí para obtener el código

Arquitectura Cliente-Servidor

El servidor ofrecerá un servicio (identificado por el número de puerto) a todos los clientes que se conecten al mismo.

Un ejemplo es el servidor HTTP, el cual devolverá páginas HTML a los clientes que accedan a él mediante un browser.

Cuando un cliente se conecta a una máquina servidora tendrá que especificar:

* Dirección IP del servidor

* Servicio que quiere utilizar (número de puerto)

Se va a ver primero un ejemplo sencillo en el cual el servidor solamente podrá aceptar una única petición.

Este ejemplo estará formado por dos archivos: Cliente2.java y Servidor2.java (haz clic en cada uno de los archivos para descargartelos).

Para compilar tendrás que realizar la siguiente secuencia:

1)javac Cliente2.java

2)javac Servidor2.java

Para la ejecución habrá que realizar cada una de las sentencias en interfaces de comandos distintas (cada uno en una shell):

1)java Servidor2 numeroPuerto

2)java Cliente2 direccionIPServidor numeroPuerto

Ejecutar primero el servidor y posteriormente el cliente.

El parámetro "numeroPuerto" será un entero que indicará el puerto sobre el cual se prestará el servicio. El parámetro "direccionIPServidor" será la dirección IP del servidor.

Código del servidor:

//Se va a crear el servidor. Para ello se usará la clase "ServerSocket"
//Tendrá una gran limitación: Solamente podrá atender a un cliente, los demás
//tendrían que esperar para ser atendidos

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

public class Servidor2
{

  static int puerto;
ServerSocket servidor;
Socket solicitudCliente;

BufferedReader entrada;
PrintWriter salida;

String lineaTextoRecibida = null;

public Servidor2(int puerto)
{

    this.puerto = puerto;
try
{
//Para crear un servidor solamente tendremos que indicar el número de puerto sobre el cual queremos realizar el servicio
//servidor = new ServerSocket(puerto);

System.out.println("Dir. servidor: " +
InetAddress.getLocalHost().getHostAddress());
System.out.println("Escuchando en el puerto " + String.valueOf(puerto));

//Se espera a que un cliente se conecte solicitudCliente = servidor.accept();
System.out.println("Solicitud de un cliente cuya dir. es: " + solicitudCliente.getInetAddress().getHostAddress());

//Se crea entrada/salida con cliente

entrada = new BufferedReader(
new InputStreamReader(
solicitudCliente.getInputStream()));
salida = new PrintWriter(solicitudCliente.getOutputStream(), true);

salida.println("Saludos del servidor " + InetAddress.getLocalHost().getHostAddress() + ", que tenga un buen dia");

System.out.println("Esperando a que el cliente introduzca un texto...");
//Mientras se reciba texto desde el servidor y el texto recibido sea distinto de la cadena "Adios"....
while (((lineaTextoRecibida = entrada.readLine()) != null) && (!lineaTextoRecibida.equals("Adios")) )
{
//Se escribe el texto recibido en la pantalla
System.out.println("CLIENTE: " + lineaTextoRecibida);
}

  }

catch(Exception e)
{
System.out.println("Problemas al crear el puerto " + new Integer(puerto).toString());
System.out.println(e.getMessage());
}

}

public static void main(String args[])
{

  int numPuerto;

if (args.length!=1)
System.out.println("Sintaxis: java Servidor2 numeroPuerto");
else
{
numPuerto= Integer.parseInt(args[0]);
Servidor2 servidor = new Servidor2(numPuerto);
}

}
//Método que será llamado automáticamente (pertenece a la clase Object)
public void finalize() throws Throwable
{
servidor.close();
solicitudCliente.close();
}
}

Código del cliente:

//Cliente que se conectará con el servidor
import java.net.*;
import java.io.*;

public class Cliente2
{

public static void main(String args[])
{

  Socket cliente = null;

//Una vía para la lectura y otra vía para la escritura
PrintWriter salida = null;
BufferedReader entrada = null;
//La siguiente variable servirá para captura todo lo que
//el usuario escriba por teclado
BufferedReader entradaEstandar;

String direccionIP = null;
String puerto = null;

String lineaTextoRecibida = null;
String lineaTextoEnviada = null;

//Recogida de parámetros
if (args.length != 2)
System.out.println("Sintaxis: java Cliente2 direccionIP puerto");
else
{

    try
{
direccionIP = new String(args[0]);
puerto = new String(args[1]);

//Las siguientes sentencias son para preparar la entrada
//public BufferedReader(Reader in)
//public InputStreamReader(InputStream in)
entradaEstandar = new BufferedReader(new InputStreamReader(System.in));

//Conexión con el servidor...

//Antes habrá que obtener un objeto del tipo InetAddress y a partir
//de éste


cliente = new Socket(InetAddress.getByName(direccionIP),
Integer.parseInt(puerto));

//PrintWriter(OutputStream out, boolean autoFlush)
//El segundo parámetro fuerza a hacer flush al buffer de salida
salida = new PrintWriter(cliente.getOutputStream(), true);
//public BufferedReader(Reader in)
//public InputStreamReader(InputStream in)
entrada = new BufferedReader(new InputStreamReader(
cliente.getInputStream()));

System.out.println("Entrada, salida creada con exito...");
System.out.println("Introduzca un texto. Para finalizar escribe " + "la cadena Adios");

//Se lee el mensaje de bienvenida del servidor y se escribe en pantalla
lineaTextoRecibida = entrada.readLine();

System.out.println("SERVIDOR: " +
lineaTextoRecibida);

//Mientras no se escriba el texto "Adios"....
lineaTextoEnviada = new String("Saludos del cliente "+ direccionIP);
while (!lineaTextoEnviada.equals("Adios"))
{
//Se lee una línea de la entrada estándar
lineaTextoEnviada = entradaEstandar.readLine();
//Si se ha escrito algo....
if (lineaTextoEnviada != null) {
//Se escribe el texto introducido por el usuario y se envía al servidor
System.out.println("CLIENTE: " + lineaTextoEnviada);
salida.println(lineaTextoEnviada);
}
}

entrada.close();
salida.close();
entradaEstandar.close();

}
catch(Exception e)
{
System.out.println("Problemas al conectar a "+
direccionIP + " con puerto " +
puerto);
System.out.println(e.getMessage());
}

  }
}
 
}    

EJERCICIO: Mediante sockets implementar un applet-cliente que obtenga la fecha y hora de un servidor(éste último será una aplicación independiente, es decir, stand-alone)


Soportar conexiones múltiples(Hilos)

Se verá una nueva versión del servidor que permita la conexión múltiple (hacer clic en este enlace para bajar el archivo)

Lógicamente habrá que compilar la nueva versión y luego en tres interfaces de comando distintas escribir las siguientes órdenes(primero la orden para arrancar el servidor):

1)java Server3 numeroPuerto

2)java Cliente2 direccionIP numeroPuerto

3)java Cliente2 direccionIP numeroPuerto

Experimenta la ejecución de cada uno de ellos para ver cómo puede atender de forma simultánea a los clientes que le soliciten el servicio.

Antes se va a ver la diferencia existente entre procesos e hilos.

Procesos

Un proceso tendrá una copia completa del código, tendrá su "propio espacio de memoria". El usuario puede estar viendo una única aplicación y sin embargo se están ejecutando múltiples procesos de forma simultánea y además en modo cooperativo (persiguen un objetivo o meta común). Para faciliar la comunicación entre procesos muchos sistemas operativos ofrecen recursos de Comunicación entre Procesos(IPC), como sockets y tuberías(pipes).

Hilos(Threads)

Los hilos comparten los recursos como memoria y archivos. Esta característica los hace más eficientes, pero la comunicación es un poco más compleja(pero esto generalmente será transparente para el programador). Para implementar un hilo habrá que extender la clase "Thread" e implementar el método "run". Para lanzar un hilo habrá que crear un objeto y después habrá que llamar al método "start" para arrancar el hilo.

Si examinamos el código del archivo bajado podremos encontrar los siguientes puntos importantes:

1) El constructor del hilo llama al método "start" lo cual provoca la llamada al método "run" del propio hilo

2) Existe un bucle infinito. En cada iteración se espera a que llegue algún cliente, y después se crea un hilo con dicho cliente:

//Bucle infinito
while(true)
{
//Se espera a que un cliente se conecte
solicitudCliente = servidor.accept();
//Cuando se conecte un cliente "lanzamos un hilo"
//totalmente dedicado a él. Por tanto habrá un hilo
//por petición.
new hiloCliente( servidor, solicitudCliente, puerto );
}


EJERCICIO: Hacer un applet que permita chatear (lógicamente el servidor será una aplicación independiente, stand-alone). Para realizarlo de forma sencilla, el texto que envíe un cliente lo recibirán todos los clientes(incluido el mismo cliente que envío dicho texto).


Volver al sumario