domingo, 29 de novembro de 2009

TCP, UDP e RMI minhas observações sobre exercício e exemplos

Obs importante, esse post é continuação, deste: http://neoramon.blogspot.com/2009/11/essa-e-descricao-de-trabalho-de.html

Link para o fonte completo:Link
http://www.4shared.com/file/162287536/b6844a93/sd_online.html


Ambiente de teste:
Sistema operacional Ubuntu Linux 9.10,
Kernel 2.6.31,
arquitetura i386
java jdk 1.6
Processador Intel Core 2 Duo 1,83 Ghz

Instruções para compilação:
Passos:
entrar na pasta dos bytecodes
ex: $HOME/NetBeansProjects/sd/build/classes/
rodar o rmiregistory
ex: /opt/jdk1.6.0_14/bin/rmiregistry 1099&
rodar o menu da aplicação
ex: /opt/jdk1.6.0_14/bin/java sd.Main
Clicar nos botões dos servidores e depois nos botões de teste e esperar pelo resultado!
Descrição dos testes:
Os teste foram feitos sem utilização de threads nos clientes, para que sejam executadas sequencialmente,

Para testar os dos cálculos foram feitas 10000 multiplicações, de 2 * 50.
tempo em nanosegundos
O tempo de execução do RMI é muito mais lento do que os de UDP e TCP, pois fica mais complexo enviando dois parâmetros em uma única função.
TCP por sua vez é mais lento que UDP, pela complexidade maior do protocolo UDP.

Dificuldade
A facilidade de implementação de uma multiplicação em RMI é muito mais simples do que em qualquer outros dos dois métodos.
Em segundo lugar achei mais simples a implementação em UDP, pois na linguagem java, existe uma classe especifica para “empacotar” os dados (DatagramPacket), diferente do TCP, que utiliza classes não pensadas especificamente para rede, (OutputStream e InputStream).
A dificuldade de implementação do TCP é aumentada pelo necessidade de ter que gerenciar um servidor (ServerSocket). No UDP o servidor é desnecessário pois o protocolo não exige, apenas temos que “ficar esperando” um pacote chegar (socket.receive(packet);). Em RMI apenas é necessário registrar o serviço no Servidor RMI (Naming.rebind("rmi://localhost:1099/CalculadoraService" , m);).


Tempo médio em nanosegundos.



Para testar os Ping pong foram feitas 64 envios de um pacote para o servidor que responde com o mesmo tamanho do pacote.
tempo em nanosegundos


TCP é mais lento que o UDP pela complexidade maior do TCP.
RMI é o mais lento de todos.

Valores em Kb / nanosegundos
64 testes de 0 a 63.

Facilidades de implementação:
RMI, a implementação utilizando RMI, foi mais simples, pois apenas é necessário definir uma classe de interface, e uma implementação da interface, não é necessário se preocupar com o tamanho máximo de cada pacote, nem em converter do tipo byte para outro formato.
A implementação com TCP e UDP foram muito parecidas, mas muito mais complexas do que a de RMI, pois necessita um planejamento de tamanho de cada pacote, e dificuldade de saber se foi o tamanho exato do pacote enviado.


Tala da execução do software

Tela de configuração dos testes

Tela de configuração das portas do servidor.

Vou mostrar os Serivodores e Clientes do exemplo para calculadora:

Servidor RMI

package sd.rmi.calculadora;

import java.rmi.Naming;

import sd.Valor;

public class Servidor implements Runnable {

private Valor valor;
public Servidor() {
valor = new Valor();

}

public void run() {
try {
Calculadora m = new CalculadoraImpl();
Naming.rebind("rmi://"+valor.getIpServidor()+":"+valor.getPortRmi()+"/CalculadoraService" , m);
}
catch( Exception e ) {
System.out.println( "Trouble: " + e );
}
}

}


Cliente RMI


package sd.rmi.calculadora;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.NotBoundException;
import java.net.MalformedURLException;
import sd.Valor;
import sd.tabela.Linha;
import sd.tabela.TabelaInterface;

public class Cliente implements Runnable {
private Valor valor;
private TabelaInterface tabela;
public Cliente(TabelaInterface tablea) {
valor = new Valor();
this.tabela = tablea;
}


public void run(){
try {
Calculadora m = (Calculadora) Naming.lookup( "rmi://"+valor.getIpServidor()+":"+valor.getPortRmi()+"/CalculadoraService" );
long t1 = 0;
long t2 = 0;


int n = valor.getnCalculadora();
long tn = 0;

System.out.println();
for (int i = 0; i <>
System.out.print(".");
t1 = System.nanoTime();
Integer resultado = m.multiplica(2, 50);
t2 = System.nanoTime();
long ta = t2-t1;
tn += ta;
Linha linha = new Linha();
linha.setN(i);
linha.setT1(t1);
linha.setT2(t2);
linha.setValor(resultado.toString());
tabela.addLinha(linha);
tabela.atualiza(true);
}

}
catch( MalformedURLException e ) {
System.out.println();
System.out.println( "MalformedURLException: " + e.toString() );
}
catch( RemoteException e ) {
System.out.println();
System.out.println( "RemoteException: " + e.toString() );
}
catch( NotBoundException e ) {
System.out.println();
System.out.println( "NotBoundException: " + e.toString() );
}
catch( Exception e ) {
System.out.println();
System.out.println( "Exception: " + e.toString() );
}
}
}

Interface RMI
package sd.rmi.calculadora;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculadora extends Remote {

public Integer multiplica( Integer n1, Integer n2) throws RemoteException;

}
Implementação da Interface RMI
package sd.rmi.calculadora;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class CalculadoraImpl extends UnicastRemoteObject implements Calculadora {

public CalculadoraImpl() throws RemoteException {
super();
}

public Integer multiplica(Integer n1, Integer n2) throws RemoteException {
return n1 * n2;
}
}

Servidor TCP

package sd.tcp.calculadora;

/**
*
* @author ramon
*/

import java.net.*;
import java.io.*;
import sd.Valor;

public class Servidor implements Runnable {
private Socket clientSocket = null;
private ServerSocket serverSocket = null;

private Valor valor;
public Servidor() {
valor = new Valor();

}

public void run() {
try {
serverSocket = new ServerSocket(valor.getPortTcpCalc());
while (true){

clientSocket = serverSocket.accept();

InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();

Integer v1 = Util.streamToInteger(in);
Integer v2 = Util.streamToInteger(in);


byte[] b = Util.integerToByte(v1*v2);

out.write(b);


out.close();
in.close();
clientSocket.close();
//serverSocket.close();
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{

serverSocket.close();
}catch(Exception e){
e.printStackTrace();
}

}


}



}

Cliente TCP

package sd.tcp.calculadora;

/**
*
* @author ramon
*/

import java.io.*;
import java.net.*;
import sd.Valor;
import sd.tabela.Linha;
import sd.tabela.TabelaInterface;

public class Cliente implements Runnable{
private Socket echoSocket = null;
private OutputStream out = null;
private InputStream in = null;

private Valor valor;
private TabelaInterface tabela;
public Cliente(TabelaInterface tablea) {
valor = new Valor();
this.tabela = tablea;
}

public void run(){
try {
long t1, t2, tn;
float tm = 0;
Integer v1 = 2, v2 = 50;
int n = valor.getnCalculadora();
tn = 0;
System.out.println();
for (int i = 0; i <>
System.out.print(".");
echoSocket = new Socket(valor.getIpServidor(), valor.getPortTcpCalc());
out = (echoSocket.getOutputStream());
in = echoSocket.getInputStream();

t1 = System.nanoTime();
out.write(Util.integerToByte(v1));
out.write(Util.integerToByte(v2));
Integer resultado = Util.streamToInteger(in);
t2 = System.nanoTime();
tn += t2-t1;
in.close();
out.close();
echoSocket.close();
Linha linha = new Linha();
linha.setN(i);
linha.setT1(t1);
linha.setT2(t2);
linha.setValor(resultado.toString());
tabela.addLinha(linha);

}
tabela.atualiza(true);
out.close();
in.close();
echoSocket.close();

} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}


}
}

Classe de Conversão Byte para integer e Integer pra byte
Existe maneira mais fácil de fazer isso, por exemplo manda como string ou integer mesmo, porém tava dando alguns problemas na hora de execução do "for", então criei essa classe para evitar problemas

package sd.tcp.calculadora;

/**
*
* @author ramon
*/

import java.io.*;
import java.net.*;
import sd.Valor;
import sd.tabela.Linha;
import sd.tabela.TabelaInterface;

public class Cliente implements Runnable{
private Socket echoSocket = null;
private OutputStream out = null;
private InputStream in = null;

private Valor valor;
private TabelaInterface tabela;
public Cliente(TabelaInterface tablea) {
valor = new Valor();
this.tabela = tablea;
}

public void run(){
try {
long t1, t2, tn;
float tm = 0;
Integer v1 = 2, v2 = 50;
int n = valor.getnCalculadora();
tn = 0;
System.out.println();
for (int i = 0; i <>
System.out.print(".");
echoSocket = new Socket(valor.getIpServidor(), valor.getPortTcpCalc());
out = (echoSocket.getOutputStream());
in = echoSocket.getInputStream();

t1 = System.nanoTime();
out.write(Util.integerToByte(v1));
out.write(Util.integerToByte(v2));
Integer resultado = Util.streamToInteger(in);
t2 = System.nanoTime();
tn += t2-t1;
in.close();
out.close();
echoSocket.close();
Linha linha = new Linha();
linha.setN(i);
linha.setT1(t1);
linha.setT2(t2);
linha.setValor(resultado.toString());
tabela.addLinha(linha);

}
tabela.atualiza(true);
out.close();
in.close();
echoSocket.close();

} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}


}
}

Servidor UDP
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package sd.udp.calculadora;

/**
*
* @author ramon
*/

import java.io.*;
import java.net.*;
import sd.Valor;
public class Servidor implements Runnable{


private Valor valor;

public Servidor() {
valor = new Valor();
}


public void parar(){


}

public void run ()
{
DatagramSocket socket = null;
try {
socket = new DatagramSocket(valor.getPortUdpCalc());
while (true) {
byte[] buf = new byte[256];

DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String str1 = new String(packet.getData(), 0, packet.getLength());

socket.receive(packet);
String str2 = new String(packet.getData(), 0, packet.getLength());

String resultado = new Integer(new Integer(str1)*new Integer(str2)).toString();
buf = resultado.getBytes();

InetAddress address = packet.getAddress();
int port = packet.getPort();

packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);

}
} catch (IOException e) {
e.printStackTrace();
}finally{
try{
socket.close();
}catch(Exception e){}
}
}

}

Cliente UDP
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package sd.udp.calculadora;

/**
*
* @author ramon
*/
/**
*
* @author ramon
*/

import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import sd.Valor;
import sd.tabela.Linha;
import sd.tabela.TabelaInterface;

public class Cliente implements Runnable{

Valor valor;
TabelaInterface tabela;
public Cliente(TabelaInterface tablea) {
valor = new Valor();
this.tabela = tablea;
}


public void run(){
DatagramSocket socket = null;
try {

InetAddress address = InetAddress.getByName(valor.getIpServidor());
DatagramPacket packet1;
DatagramPacket packet2;
DatagramPacket packet3;
int n = valor.getnCalculadora();
byte[] buf1 = new String("2").getBytes();
packet1 = new DatagramPacket(buf1, buf1.length, address, valor.getPortUdpCalc());
byte[] buf2 = new String("50").getBytes();
packet2 = new DatagramPacket(buf2, buf2.length, address, valor.getPortUdpCalc());
byte[] buf3 = new byte[256];
packet3 = new DatagramPacket(buf3, buf3.length);
long t1 = 0;
long t2 = 0;
System.out.println();
socket = new DatagramSocket();
for (int i = 0; i < t1 =" System.nanoTime();" t2 =" System.nanoTime();" resultado =" new" linha =" new">

Nenhum comentário: