Archive for the ‘Escritorio Remoto’ Category

Transfiriendo archivos usando Java de la forma incorrecta

Hoy en día les mostrare como transferir archivos en java de la forma incorrecta.
La razón de este artículo es que un amigo me pidió ayuda de cómo transferir archivos a pesar que le dije como hacerlo, no logró hacerlo de la manera correcta(hasta donde yo se). Y por asuntos didácticos dividiré este artículos en dos partes (transfiriendo archivos de manera incorrecta y correcta).

El siguiente código que les mostraré como transferir el archivo de la forma incorrecta, espero que al leerlo se de cuenta de cual es el error.

Primero debemos crear el servidor, primero el código para aceptar una simple conexión

ServerSocket server = new ServerSocket(1234);
Socket conexion = server.accept();        

Básicamente lo que hacemos es crear un ServerSocket el cual se pone a la escucha en el puerto 1234 (un numero cualquiera pero debe ser superior a 1024). La siguiente linea lo que hace es esperar una conexión (esta función se bloquea hasta que alguien se conecte al puerto abierto) y devolverá un objeto Socket el cual manejará la conexión.

Luego debemos enviar el archivo (de la manera mala)

File transfer = new File("~/archivo pequeño.doc");
FileInputStream fin = new FileInputStream(transfer);
byte datos[] = new byte[fin.available()]; ///noten esto
fin.read(datos);
OutputStream out = conexion.getOutputStream();
out.write(datos);
out.flush();
out.close();
conexion.close();

Básicamente hemos transferido nuestro archivo de mala manera, pero también nos falta recibir nuestro archivo también de mala manera

Socket descargar = new Socket("localhost",1234);
InputStream in = descargar.getInputStream();
byte descarga[] = new bytes[in.avalaible()]; //noten esto
in.read(descarga);
FileOutputStream fout = new FileOutputStream(new File("~/archivo transferido.doc"));
fout.write(descarga);
descargar.close();

En las partes que les mencione en el código (noten esto) se darán cuenta que nuestro programa puede quedarse sin memoria al tratar de transferir un archivo muy grande.

Bueno espero que tengán deduzcan la forma correcta de transferir archivos antes que yo la postee, Saludos!!

Nota:Avisar si hay algún error, hice a la rapida este articulo :S

Programando un explorador de archivos simple

Hoy en dia mostrare algunas cuantas funciones para mostrar los archivos a esto lo llamaremos una Herramienta para nuestro escritorio remoto  a futuro estas herramientas en nuestro escritorio remoto seran como un plugin ahora solo mostrare de manera sencilla como mostrar archivos y directorios por ahora de tu computador personal de manera muy local.

Para esto solo usaremos las clases File para acceder a los archivos y directorios y PrintStream para mostrar algo en pantalla.

-Importacion del codigo

package egyware.sample;



import java.io.File;

import java.io.PrintStream;


-Creación de la clase

public class FileExplorer {

	//Preparamos 

	public static File roots[] = File.listRoots();

	/**

	 * @param args

	 */

	public static void main(String[] args) {

		showDir(System.out,null);	

		showDir(System.out,"/");

                //showDir(System.out,"c:\");



	}

-Implementación de la función que muestra los archivos y directorios

	public static void showDir(PrintStream out,String dir){
		if(out==null)
			return;
		File files[] = null;
		out.print('>');
		if(dir == null){
			out.println("roots:");
			files = roots;
		}
		else{
			File f = new File(dir);
			if(f.isFile()){
				out.println("es un archivo");
				return;
			}				
			out.println(f.getPath()+":");
			files = f.listFiles();
		}
		for(int i=0;i<files.length;i++){
			String name = files[i].getName();
			//Parche para el root en linux
			if(name.length()>0)
				out.println(name);
			else
				out.println(files[i].getAbsoluteFile());
		}	
		
	}
}

Es posible que no lo hayan notado, pero aqui las funciones mas importantes son:
File.listRoots()
new File(dir).listFiles()
La primera función estatica nos devuelve un arreglo de la lista de Roots, en linux nos devuelve solo “/” pero en windows nos devuelve las unidades conectadas al pc “c:”,”d:”,…
La segunda función de objeto nos devuelve el contenido del “dir“, siempre y cuando “dir” sea un directorio si no es asi devolvera null, por eso la comprobacion en la linea 12 de la implementación de la función.
Además en la linea 21 de la implementación de la función puse un parche para el root de linux, ahora ¿por qué? porque la funcion getName cuando pido el nombre de “/” no devuelve nada (esto no es un error, es que no tiene nombre simplemente).
Bueno eso es todo.

Programando un servidor no tan simple con conexión alternada (parte 2)

Como se mostro en el tutorial anterior se mostro como hacer una coneccion directa pero a la vez se puede alternar.  Bueno el tema anterior deja varias dudas como por ejemplo ¿si quiero montar un servidor? con coneccion alternada como lo hago.  Entonces para eso haremos usaremos reflección, aunque tambien podemos usar Interfaces si es que lo deseamos, pero con otros ajustes. Nuestro prototipo de función (Como C) será:

public static boolean createConetion(String ip,int port,boolean direct,Class<?> clase,Object args[])

Para empezar los primeros parametros se ven casi triviales pero el ultimo puede ser un poco confuso. El penultimo parametro aceptara solo la clase NetHandler que la definiremos despues, ya que si aceptaramos todas las clases seria todo un lío definiendo limites para todo tipo de clases. Con el objeto Class podremos instanciar nuevos objetos y dependiendo del objeto lo haremos ejecutar de distintas formas. Y en caso que nuestra clase que hereda de NetHanlder requiera mas parametros se los pasaremos de forma de arreglo de objetos :).

//File NetHandler.java
//package egyware.net;
import java.io.*;
import java.net.*;
/**
* Clase que permite crear un controlador de red
* @author Edgardo
*/
public abstract class NetHandler{
//Defino la E/S Raw (solo bytes) del stream
protected InputStream rawIn;
protected OutputStream rawOut;
protected Socket conex;
public NetHandler(Socket socket) throws IOException{
conex = socket;
rawIn = socket.getInputStream();
rawOut = socket.getOutputStream();
}
/**
* Desde aqui se empezara a ejecutar el hilo
* definir este metodo para controlar tu coneccion de red
*/
public abstract void run();
}

Ya perfecto tenemos definida nuestra clase que nos permetira ejecutar todo tipo controladores de conecciones, pero solo nos permitira ejecutar una conexión no más, para ese caso si deseamos más conexiones implementaremos Runnable y como el metodo que se usa es el mismo en NetHandler es el mismo entonces no habrá problemas en cambiar los metodos de lugar.
Nuestra clase EcoThread usando NetHandler

//File EcoHandler.java
//package egyware.sample
//import egyware.net
public class EcoHandler extends NetHandler implements Runnable{
public EcoHandler(Socket socket) throws IOException {
super(socket);//Contruyendo la clase madre
}
public void run(){
byte buffer[]=new byte[512];
while(true){
if(rawIn.available()>0){
int reads = rawIn.read(buffer,0,buffer.length);
if(reads>0)
rawOut.write(buffer, 0, reads);
}
}
}

Y eso es todo para nuestro EcoHandler ahora nuestra feisima función(lo llamo asi porque sera compleja)

-Importación de clases y función main.

import egyware.sample.*;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.*;
import java.util.Arrays;
import java.util.LinkedList;
public class Server {
private static boolean stop = false;
public static void main(String args[]) throws IOException {
boolean b = createConection("localhost", 3040, true, EcoHandler.class,null);
}

-Revisar que se implemente Runnable

public static boolean createConection(String ip, int port, boolean direct,
Class<?> clase, Object args[]) {
Socket conexion = null;
// Revisamos si implementa Runable
boolean runnable = false;
Class<?> interfaces[] = clase.getInterfaces();
for (int i = 0; i < interfaces.length; i++)
if (interfaces[i] == Runnable.class) {
runnable = true;// Si lo implementa
break;// salimos del for para evitar buscar en otras interfaces
}

-Revisar que herede de NetHandler

// Ademas revisamos que la clase herede de NetHandler para eso debera
// aceptar un casting
try {
clase.asSubclass(NetHandler.class);
} catch (ClassCastException cce) {
// Si falla, retornaremos falso que no pudo
cce.printStackTrace();
return false;
}

-Buscando el constructor deseado, para esta ocasion

// buscamos el constructor que necesitamos
Constructor<?> c[] = clase.getConstructors();
Constructor<?> constructor = null;
// Debemos buscar algo que ajuste a lo que no han pasado
// debemos buscar un constructor con args.length+1 parametros
int length = (args != null) ? args.length + 1 : 1; // Minimo debe tener
// 1 constructor
for (int i = 0; i < c.length; i++) {
// Debe coincidir el largo de parametros y el primer tipo debe ser
// Socket
if (length == c[i].getParameterTypes().length && c[i].getParameterTypes()[0] == Socket.class) {
constructor = c[i];
break;// Salimos del for
}
}
// No encontramos un constructor apropiado, nos salimos
if (constructor == null)
return false;

-Preparando la lista de argumentos

// Lista de argumentos: la preparamos antes como no cambia
Object argumentos[] = null;
// Declaro un bloque para que lista, no se use mas y se valla al GC
{
LinkedList<Object> lista;
if (args != null)
lista = new LinkedList<Object>(Arrays.asList(args));
else
lista = new LinkedList<Object>();
lista.addFirst(null);// Dejamos un espacio
argumentos = lista.toArray();
// Sugerimos a la VM usar el Garbage Collector o GC
System.gc();
}

-Conexión directa y las dos formas de recibir una conexión

if (direct) {
// Nos ponemos a la escucha de todas las interfaces en el puerto
// 3040
ServerSocket server;
try {
// creamos una nueva instancia
server = new ServerSocket(port);
// bueno ahora segun si implementa o no vamos a definir una
// actitud
if (runnable) {
// un while
while (!stop) {
// Aceptamos una conección
conexion = server.accept();
// si hay una nueva coneccion crear un nuevo objeto
argumentos[0] = conexion;// para eso necesitabamos espacio en blanco
// pasamos los argumentos
Object run = constructor.newInstance(argumentos);
//Sin problemas realizamos el Casting y iniciamos el Thread
new Thread((Runnable) run).start();
}
server.close();
} else {
// Aceptamos una sola conección
conexion = server.accept();
// si hay una nueva coneccion crear un nuevo objeto
argumentos[0] = conexion;/*
* para eso necesitabamos el espacio
* en blanco
*/
Object run = constructor.newInstance(argumentos); /*
* pasamos
* los
* argumentos
*/
// Cerramos para que no acepte ninguna otra coneccion
server.close();
// Realizamos un casting sin problemas a NetHandler
((NetHandler) run).run(); // Ejecutamos
}
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
} catch (InstantiationException e) {
e.printStackTrace();
return false;
} catch (IllegalAccessException e) {
e.printStackTrace();
return false;
} catch (InvocationTargetException e) {
e.printStackTrace();
return false;
}
return true; // Si llego hasta aqui no hubo ningún problema

-Conexión inversa y las dos formas de conectarnos al servidor

} else {
// Ahora que terminamos con la coneccion directa, ahora con la
// indirecta
// Notar que el comportamiento sera un tanto distinto
if (runnable) {
// Nos conectamos he iniciamos 1 solo Thread
try {
conexion = new Socket(ip, port);
argumentos[0] = conexion;
Object run = constructor.newInstance(argumentos);
// Y eso es todo
new Thread((Runnable) run).start();
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
} catch (InstantiationException e) {
e.printStackTrace();
return false;
} catch (IllegalAccessException e) {
e.printStackTrace();
return false;
} catch (InvocationTargetException e) {
e.printStackTrace();
return false;
}
} else {
// Ahora el otro, este caso trataremos de mantener siempre una
// coneccion activa
// Si se cierra la volvemos abrir
try {
while (!stop) {
conexion = new Socket(ip, port);
Object run = constructor.newInstance(argumentos);
// Hacemos ejecutar el NetHandler hasta que pierda la
// coneccion
((NetHandler) run).run();
}
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
} catch (InstantiationException e) {
e.printStackTrace();
return false;
} catch (IllegalAccessException e) {
e.printStackTrace();
return false;
} catch (InvocationTargetException e) {
e.printStackTrace();
return false;
}
}
//Si hemos llegado aqui esque todo salio de maravilla
return true;
}
}
}

Bueno hemos terminado con esta segunda parte dejo el link para que descarguen el fuente
Fuente

PS: Me he dado cuenta que el WordPress es pesimo para mostrar fuente, asi que para la proxima colocare solo puntos claves, en este caso era la reflección.
PD: Gracias a Rodrigo por el tag sourcecode, queda mas ordenado el codigo 😉
UPDATED: He divido el codigo para una mejor entendimiento.

Programando un servidor simple con conexión alternada (parte 1)

Hola a todos como me prometí en algún tiempo en crear una API o algo parecido en Java para facilitar la creación de escritorios remotos. También iré enseñando como se hace paso a paso para que aprendan también.

Para este tutorial crearemos un servidor eco y un cliente que se conectara usando la pequeña api que empezara aparecer. En donde primero se creara una función que puede alternarse la forma de conectarse a él (directa e inversa).
Asumo que ya saben java asi que omitiré ciertos comentarios.

Primero programaremos el servidor

//Server.java
package egyware.net;
import egyware.sample.*;
import java.io.IOException;
import java.net.*;
public class Server{
public static void main(String args[]) throws IOException{
String ip="localhost";
int port = 3040;
//Si nuestra conexión es directa o inversa
boolean directo=true;
//Nuestra conexión
Socket conexion = null;
if(directo){
//Nos ponemos a la escucha de todas las interfaces en el puerto 3040
ServerSocket server = new ServerSocket(port);
conexion = server.accept();/*Nos ponemos a la escucha hasta que alguien llegue =D */
}else{
//Nos conectamos a la dirección proporcionada anteriormente
conexion = new Socket(ip,port);
}
//Nota(1):Continuaremos aquí después
}
}

Atención con esa nota que luego seguiremos ahí.
Esta claro que podemos alternar el tipo de conexión de distintas maneras solo cambiando una variable ahora esto no tiene mucha utilidad pero para nuestra biblioteca, si lo será.

Continuemos con la Nota (1) .
Aquí es donde manejaremos la conexión. Yo no he visto otras maneras de manejar la conexión mas que usando Threads en Java pero en C/C++ maneje múltiples conexiones usando un solo hilo pero asignado un tiempo a cada uno. En este caso usaremos la hilos, es mas fácil esta más orientada a objetos ya que nos desligaremos de otras cosas y solo manejaremos una conexión ya sea como servidor o como cliente.
Nota (1)

new EcoThread(conexion).run()
// No ejecute el Thread como tal,
// pero si quieres en vez de run() usa start()
//EcoThread.java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class EcoThread extends Thread{
private Socket conex;
private InputStream in;
private OutputStream out;
public EcoThread(Socket s) throws IOException{
conex = s;
in = conex.getInputStream();
out = conex.getOutputStream();
}
public void run(){
//Existen muchas maneras de hacer este server
byte buffer[]=new byte[512];
try {
while(true){
if(in.available() > 0){
int reads = in.read(buffer,0,buffer.length);
if(reads&gt;0)
out.write(buffer, 0, reads);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Si lo compilan y lo ejecutan solo para probar realmente funcionará lo pueden probar usando el comando “telnet localhost 3040” Repetirá toda tecla que es enviada, pero razones que desconozco no repite la primera >.< Para cerrar el programa tiene que forzar la salida.
Terminare con esta primera parte(para que no se aburran de leer xD) para dejar a la segunda que es la implementación de la función usando un poco de reflección para ello adiós.

Fuentes