1. Instituto Tecnológico de La Laguna
Maestría Profesional en Sistemas Computacionales
Practica I
Intercomunicación con sockets en Java
Materia
Computación Paralela y Distribuida
Dr. Luis
Alumno
Iribe González Jesús Alberto
Abril de 2013
2. Índice
Introducción ..........................................................................................................1
Análisis del problema ...........................................................................................2
Objetivo .................................................................................................................4
Java ........................................................................................................................4
Socket ....................................................................................................................4
Servidor..................................................................................................................4
Cliente....................................................................................................................4
Conclusiones........................................................................................................13
Bibliografía.............................................................................................................1
3. Introducción
La práctica consistirá en la implementación y puesta a punto de un cliente simple, que
realizará un número suficiente de llamadas a un servidor utilizando los métodos
descritos más adelante. Tras lo anterior, el objetivo es medir el tiempo consumido por
cada llamada. Se utilizarán tres tipos de servidores:
1. Un objeto local.
En este caso, se está midiendo el coste de una llamada a subrutina local.
2. Un proceso esperando peticiones vía UDP.
3. Un proceso esperando peticiones TCP.
Adicionalmente, para los tipos 2 y 3, se considerarán dos formas de localizarlos:
1. El servidor y el cliente están en el mismo nodo.
2. El servidor está en un nodo distinto al del cliente.
Los servidores de tipo 2, y 3, son implementados dentro de un programa que se
suministra con la práctica. Su lectura es aconsejable. Dicho programa podrá ser
ejecutado con tres parámetros: servidor (t�u) puerto duración
Los parámetros tienen el siguiente significado:
1. El primero indica TCP/IP si su valor es t, o UDP/IP si su valor es u.
2. El segundo indica el puerto en que esperará la petición.
3. El tercero indica cuánto tiempo se va a tardar en ejecutar la petición. La duración
está expresada en milisegundos. Para la primera práctica, el tercer parámetro será
opcional, y su ausencia indicará un valor igual a 0. Eso querrá decir que el objeto
servidor no retardará en absoluto la contestación al cliente.
En el caso 1, el servidor es un objeto. Dicho objeto deberá ser implementado en el
propio programa cliente, y deberá también tener un método llamado servicio local,
que será invocado por el cliente.
El código de cliente deberá ser escrito por el alumno. El esquema del código a
desarrollar por la función principal aparece en la figura. La forma exacta en que sea
llamado el servidor dentro del bucle debe ser implantada de la forma que se crea más
conveniente, aunque se aconseja la creación de una clase intermedia que incorpore
tres métodos. Uno de ellos para la invocación local, otro para la UDP y el tercero para
la TCP.
NOTA: Será necesario especificar por medio de parámetros del programa cliente: los
valores de MAXLOOP, el puerto de contacto con el servidor, el nodo donde reside el
servidor, y el método de contacto (TCP/UDP/local).
Algoritmo para programación de Cliente
4. public class Cliente
public static void main( String[] args )
Tomar tiempo
for (i = 0; i < MAXLOOP; i++)
Enviar mensaje al servidor �
Esperar respuesta del servidor
}
Tomar tiempo
tiempo por llamada = Dif. de tiempo/MAXLOOP
}
}
Análisis del problema
El problema principal consiste en utilizar las clases DatagramPacket, DatagramSocket,
InetAddress y Socket para establecer comunicación en una red local entre dos
maquinas una denominada como servidor y la otra como cliente.
Objetivo
El objetivo de la primera práctica es por una parte, familiarizar al alumno con el uso de
las herramientas de construcción programas en Java, y por otra conseguir que el
alumno alcance a apreciar el coste de la realización de llamadas a un servidor en
diferentes modalidades.
5. Java
Java es una tecnología que se usa para el desarrollo de aplicaciones que convierten a la
Web en un elemento más interesante y útil. Java no es lo mismo que java script, que se
trata de una tecnología sencilla que se usa para crear páginas web y solamente se
ejecuta en el explorador.
Java le permite jugar, cargar fotografías, chatear en línea, realizar visitas virtuales y
utilizar servicios como, por ejemplo, cursos en línea, servicios bancarios en línea y
mapas interactivos. Si no dispone de Java, muchas aplicaciones y sitios web no
funcionarán.
Por defecto, Java le notificará inmediatamente que hay nuevas actualizaciones listas
para instalarse. Si desea estar al día y mantener la seguridad de su computadora, es
importante que acepte e instale las actualizaciones. Si recibe una notificación de
actualización de Java en su computadora Windows y no recuerda haberla descargado o
instalado, lo más probable es que Java estuviera ya instalado en la nueva
computadora.
Tiene una página de referencia a todas las clases interfaces y demás componentes en
esta dirección web http://docs.oracle.com/javase/6/docs/api/
6. Socket
Los sockets son un sistema de comunicación entre procesos de diferentes máquinas de
una red. Más exactamente, un socket es un punto de comunicación por el cual un
proceso puede emitir o recibir información.
Fueron popularizados por Berckley Software Distribution, de la universidad
norteamericana de Berckley. Los sockets han de ser capaces de utilizar el protocolo de
streams TCP (Transfer Control Protocol) y el de datagramas UDP (User Datagram
Protocol).
Utilizan una serie de primitivas para establecer el punto de comunicación, para
conectarse a una máquina remota en un determinado puerto que esté disponible, para
escuchar en él, para leer o escribir y publicar información en él, y finalmente para
desconectarse.
Con todas primitivas se puede crear un sistema de diálogo muy completo.
Interfaz de Usuario
La interfaz es una misma para ambas aplicaciones, sin embargo, en tiempo de
ejecución el usuario podría definir si usarla como cliente o como servidor. A
continuación se explican cada uno de los elementos del formulario:
Tipo
Define el tipo de comunicación que se va a establecer en el
servidor o el cliente. En este ejercicio se hicieron pruebas con los
tres tipos de comunicación indicados en la imagen.
7. Host
Define la dirección donde se debe buscar el servidor para que reciba el mensaje.
Puerto
Indica el puerto donde está funcionando el servidor o puerto donde el servidor recibirá
el mensaje
Iniciar
Inicia el servicio de servidor con los parámetros establecidos
Enviar
Envía un número vinario en este caso un 100 al puerto y servidor que se le indique, el
servidor debe responder con un carácter binario 65.
8. Servidor
A continuación se muestra el código que se utilizo para la implementación del servidor.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;
import javax.swing.JOptionPane;
public class Servidor extends Thread{
Socket so;
long dur;
ServerSocket ss;
InputStream is;
OutputStream os;
private BufferedReader entrada;
public Servidor(String tipo,Integer port, Integer d){
Long [] t=new Long[2];
boolean udp = false;
boolean MT = false;
long duration = d;
String args2[]=new String[3];
args2[0]=tipo;
args2[1]=port.toString();
args2[2]=Long.toString(d);
if (args2.length < 2) {
System.out.println("Numero de argumentos erroneo");
return;
}
if(args2[0].equalsIgnoreCase("u")) {
System.out.println("Servidor UDP");
udp = true;
}else if(args2[0].equalsIgnoreCase("t")){
System.out.println("Servidor TCP");
udp = false;
}else{
System.out.println("Servidor TCP MT");
MT = true;
}
try {
port = (new Integer(args2[1])).intValue();
}catch (Exception e) {
System.out.println(args2[1] + "no es un numero valido de puerto");
return;
}
if (args2.length == 3) {
try {
9. duration = (new Long(args2[2])).longValue();// La duracion no puede ser
negativa. //
if (duration < 0) {
duration = -duration;
}
}catch(Exception e) {
System.out.println(args2[2] + "no es un valor adecuado de duracion.");
return;
}
}else {
duration = 0;
}// Logica del programa. //
if (udp) {
serverudp(port,duration);
}else if (MT) {
servertcpmt(port,duration);
}else {
servertcp(port,duration);
}
}
class multi implements Runnable {
public multi(Socket s, long duration) {
so = s;
dur = duration;
}
@Override
public synchronized void run(){
try {
InputStream is = so.getInputStream();
OutputStream os = so.getOutputStream();
int ch;
ch = is.read();
if ( dur > 0 ) {
wait(dur);
}
System.out.println("Dato recivido: "+ch);
os.write(65);
so.close();
} catch (IOException e){
System.out.println("Algo fue mal");
} catch (InterruptedException e){
System.out.println("Adios");
}
}
}
// Metodo a utilizar con un cliente UDP. //
10. public synchronized void serverudp(int port, long dur){
DatagramSocket ds; // Socket para UDP. El contenido del paquete UDP va a //
// ser un vector de bytes con una sola componente. //
byte[] buf = new byte[1];// El paquete UDP se crea con el vector anterior. //
DatagramPacket dp = new DatagramPacket(buf,1);
try {// Hay que crear un socket UDP asociado al puerto especificado como primer
argumento. //
ds = new DatagramSocket(port);
} catch (Exception e) {
System.out.println("No se ha podido asociar el socket UDP al puerto " + port);
return;
}
while (true){
try{// Se recibe una petici´on por parte del cliente. Una vez obtenida hay que //
// esperar el tiempo indicado para simular la ejecucion de la peticion. //
ds.receive(dp);
if ( dur > 0 ) {
wait(dur);
}// Al final se contesta, reenviando el mismo paquete recibido. //
if(dp.getLength()>0) {
String recivido = new String(dp.getData());
System.out.println("Dato recibido: "+recivido);
ds.send(dp);
}
}catch (IOException e) {
System.out.println("No se ha podido recibir.");
return;
}catch (InterruptedException e){
System.out.println("Adios");
return;
}
}
}
public synchronized void servertcp(int port, long dur) {
try {// Se crea el socket Servidor ss, asociandolo al número de puerto especificado
como primer argumento. //
ss = new ServerSocket(port);
System.out.println("Puerto "+port+" asociado al socket TCP.");
}catch (Exception e) {
System.out.println("No se puede asociar el puerto "+port+" al socket TCP.");
return;
}
while (true) {
try {// Esperar conexion por parte del cliente y generar un nuevo socket para
atenderla cuando se establezca. //
so = ss.accept();// "is" va a permitir la lectura de informacion existente en el
socket. //
11. is = so.getInputStream();// "os" se utiliza para escribir informacion que podra
obtener el cliente. //
os = so.getOutputStream();
int ch;
ch = is.read();// Esperar hasta poder leer un byte. //
if(String.valueOf(ch).length()>0) {
System.out.println("Dato recivido: "+ch);
}
if ( dur > 0 ) {
wait(dur);
}// Simular la atencion de la peticion. //
os.write(65);// Enviar la respuesta. //
so.close();// Cerrar el socket utilizado para esta conexion. //
}catch (IOException e) {
System.out.println("Algo fue mal");
}catch (InterruptedException e) {
System.out.println("Adios");
}
}
}
// Version TCP con mutiples hilos. //
public synchronized void servertcpmt(int port, long dur) {
try {// Asociar un puerto al socket Servidor a utilizar para esperar las conexiones
de los clientes. //
ss = new ServerSocket(port);
}catch (Exception e) {
System.out.println("No se puede asociar el puerto "+port+" al socket TCP.");
return;
}
while (true){
try {// Aceptar las conexiones de los clientes, creando un nuevo socket por cada
una de ellas. //
so = ss.accept();// Crear un thread "multi" que sirva la peticion que acaba de
llegar. //
new Thread(new multi(so,dur)).start();
}catch(IOException e) {
System.out.println("Algo fue mal");
}
}
}
}
12. Cliente
El código del cliente fue implementado bajo el algoritmo que se solicito en la práctica.
import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
public class Cliente {
String host;
Integer puerto;
Socket sc;
DataOutputStream mensaje;
DataInputStream entrada;
BufferedReader entradabr;
byte[] sendData = new byte[1];
byte[] receiveData = new byte[1];
byte dato=100;
String cadena;
Long[] t=new Long[2];
public Cliente(String host, Integer puerto){
this.host=host;
this.puerto=puerto;
}
public void tcp(){
try {
sc = new Socket(host,puerto);
System.out.println("Enviando mensaje: "+dato+" Puerto "+puerto+" Socket
TCP.");
mensaje = new DataOutputStream(sc.getOutputStream());
t[0]=System.currentTimeMillis();
mensaje.write(dato);
entrada= new DataInputStream(sc.getInputStream());
t[1]=System.currentTimeMillis();
System.out.println("Recivido: "+entrada.read()+" Tiempo: "+t[1]+"-
"+t[0]+"="+(t[1]-t[0]));
sc.close();
} catch (UnknownHostException ex) {
Logger.getLogger(Cliente.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Cliente.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void udp() throws SocketException, UnknownHostException, IOException{
byte[] buf = new byte[1];// El paquete UDP se crea con el vector anterior. //
buf[0]=dato;
13. InetAddress IPAddress = InetAddress.getByName(host);
DatagramSocket clientSocket = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(buf,1);
try {
DatagramPacket sendPacket = new DatagramPacket(buf, buf.length, IPAddress,
puerto);
t[0]=System.currentTimeMillis();
clientSocket.send(sendPacket);
t[1]=System.currentTimeMillis();
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
clientSocket.receive(receivePacket);
String modifiedSentence = new String(receivePacket.getData());
System.out.println("Respuesta:" + modifiedSentence+" Tiempo: "+t[1]+"-
"+t[0]+"="+(t[1]-t[0]));
clientSocket.close();
} catch (Exception e) {
System.out.println("No se ha podido asociar el socket UDP al puerto " + puerto);
return;
}
}
}
14. Conclusiones
Tanto el cliente como el servidor fueron probados en una red local inalámbrica con
equipo que soportaba hasta el estándar de IEEE conocido como 802.11g que soporta
hasta 54 MBps y los resultados enviando 50 iteraciones con un solo byte fueron de
402,375 milisegundos equivalentes a 402.375 segundos o 6.70625 minutos.
Dado que se necesita u socket creado en java por cada mensaje que enviaremos desde
el cliente se relentiza mucho el envío y recepción de un byte, según las características
del equipo con que se pruebe esto debería mejorar notablemente.
El código mostrado anteriormente representa las clases de Servidor y Cliente
respectivamente por lo que requerirá de su implementación bajo un método main de
un proyecto a continuación se establece el modo de uso:
Iniciación del servidor
Esto esta implementado a travez de la interfaz que se mostro al inicio en el botón
Iniciar:
if(this.initserver.getText()=="Iniciar"){
Integer p;
String tipo;
p=Integer.parseInt(this.puertoservidor.getText());
switch(this.tiposervidor.getSelectedIndex()){
case 0: tipo="t"; break;
case 1: tipo="u"; break;
case 2: tipo="tu"; break;
default: tipo="t";
}
//JOptionPane.showMessageDialog(null, this.tiposervidor.getSelectedIndex());
this.initserver.setText("Terminar");
server= new Servidor(tipo,p,Integer.parseInt(this.puertoservidor.getText()));
}
Instanciación del cliente
cliente=new Cliente(this.hostclient.getText(), Integer.parseInt(this.puertoclient.getText()));
Integer limite=Integer.parseInt(this.rclient.getText());
for(int i=0;i<limite;++i){
switch(this.tipoclient.getSelectedIndex()){
case 0: cliente.tcp(); break;
case 1:try {
cliente.udp();
} catch (SocketException ex) {
Logger.getLogger(ClienteServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnknownHostException ex) {
Logger.getLogger(ClienteServidor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ClienteServidor.class.getName()).log(Level.SEVERE, null, ex);
}