Inicio > Proyectos > Administrar Remotamente un Equipo Vía Web [Java+HTML+JQuery=Remote Control]

Administrar Remotamente un Equipo Vía Web [Java+HTML+JQuery=Remote Control]

El otro día hablando con @PabloVidela y @DavidAcevedo… y Acevedo, salió la idea de administrar un computador remotamente vía Web.

¿Cual es la idea?

Poder acceder a un computador remotamente vía web, pudiendo ver el escritorio e ir navegando por él solo con el navegador…

Seguro que la idea ya está desarrollada por alguna otra persona, pero igual lo investigue.

Para poder hacer ésto, es necesario que el computador que se quiera acceder tenga algún software que cree una especie de servidor para poder conectarse a el por algún cliente.

Primero que todo crearemos el servidor. Java Tiene una clase para poder crear un servidor web rápidamente, su nombre es HttpServer (Nombre Original xD). Para que sea un servidor web debemos poner a escuchar el puerto 80, en código para ésto seria así:

 HttpServer server = HttpServer.create(new InetSocketAddress(80), 0);

Supongamos que a el servidor queremos acceder con la siguiente dirección:

http://localhost:80/hola?action=view

de eso podemos sacar los siguientes términos:

http://{host}:{puerto}/{path}?{parametros}

Ahora debemos manipular los paths de nuestro servidor.Cuando llame a algun path el servidor deberá hacer alguna tarea.

Para manipular los paths debemos implementar la interface HttpHandler

//## Implementar interface HttpHandler
public class Servidor implements HttpHandler  {
    //## Constructor
    public Servidor() {
            //## Creo el Servidor en el puerto 80
            HttpServer server = HttpServer.create(new InetSocketAddress(80), 0);
            //## llamo al metodo createContext para poder hacer alguna funcionalidad al llamar al path "/get"
            server.createContext("/get", this);
            server.

    }
    //## Implementamos el Método handle de la interfaz HttpHandler
    public void handle(HttpExchange he) throws IOException {
        //## Acá agregamos la funcionalidad para los paths
        //...
    }
}

Ahora tenemos dos cosas que programar.

  • Capturar una imagen del escritorio: Con esto tendremos, en una imagen, lo que el servidor esta haciendo, las ventanas abiertas y todo lo que se pueda ver en el escritorio.
  • Clickear en un punto dado: con esto podremos, clickear en el escritorio segun parametros X e Y.

La primera tarea que programaremos es que al llamar a la URL

http://servidor:80/get

nos devuelva una imagen del escritorio del servidor.
Para eso usaremos la clase Robot de java. Esta clase se utiliza para generar eventos nativos de entrada del sistema a efectos de la automatización de pruebas, demos autoejecutables, y otras aplicaciones donde el control del ratón y el teclado es necesario. (API Java).

Con el siguiente método capturaremos el escritorio en una imagen

package servtest;

import java.awt.AWTException;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;

/**
 *
 * @author Esteban Fuentealba
 */
//## Creamos una Clase llamada ScreenShot
public class ScreenShot {

    public ScreenShot() {
    }
    public Image get() throws AWTException {
        //## Creamos una instancia a la Clase RObot
        Robot robot = new Robot();
        //## Tomamos una fotografía (Screen Shot) del Escritorio
        BufferedImage bufferedImage = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
        //## Retornamos una Image
        return Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource());
    }

}

Ahora, con una imagen podríamos obtener las coordenadas de un punto específico y simular un click dependiendo de esas coordenadas, para eso utilizaremos la siguiente Clase:

package servtest;

import java.awt.AWTException;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;

/**
 *
 * @author Esteban Fuentealba
 */
public class PCControl {
    private Robot robot;
    public PCControl() throws AWTException {
        robot = new Robot();
    }
    //## Metodo que clickea en un Punto pasado como parametro
    public void click(Point punto) {
        //Movemos el mouse a la posición X e Y
        robot.mouseMove(punto.x, punto.y);
        //Simulamos el click
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
    }
}

Bueno teniendo esas dos funcionalidades crearemos el programa en Si

package servtest;

import servtest.utils.ImageUtils;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.awt.AWTException;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import servtest.utils.Utils;

/**
 *
 * @author Esteban Fuentealba
 */
public class Servidor implements HttpHandler  {
    //## Main
    public static void main(String[] args) {
        if(args.length > 0) {
            if(Utils.isNumber(args[0])) {
                new Servidor(Integer.parseInt(args[0]));
            }
        } else {
            System.out.println("Falta el numero del puerto");
        }

    }
    //## Constructor con parametros, recibe el puerto que se quiere escuchar, donde se accederá
    public Servidor(int puerto) {
        try {
            //Ponemos a escuchar el puerto
            HttpServer server = HttpServer.create(new InetSocketAddress(puerto), 0);
            // Creamos un Context para manipular el path /get
            server.createContext("/get", this);
            // Creamos otro Context para manipular el path /click
            HttpContext conClick = server.createContext("/click", this);
            // el context tendrá además parametros, los cuales filtraremos y manipularemos con la clase ParameterFilter
            conClick.getFilters().add(new ParameterFilter());
            server.setExecutor(null); // creates a default executor
            //Iniciamos el servidor
            server.start();
            System.out.println("[INFO] Server ON ");
        } catch (IOException ex) {
            Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    //## Constrctor por defecto, escucha el puerto 8080
    public Servidor() {
        this(8080);

    }
    //Implemento un metodo de la interface HttpHandler
    public void handle(HttpExchange he) throws IOException {
        System.out.println("[INFO] Connected ["+he.getRemoteAddress()+"] , Path: "+he.getHttpContext().getPath());
        //## Agrego una condición para ver que path fue llamado
        //## Si se llamo la url "http://miip:puerto/get" hare lo siguiente
        if(he.getHttpContext().getPath().equals("/get")) {
            try {
                //Creo un Objeto ScreenShot
                ScreenShot ss = new ScreenShot();
                //Capturo la imagen y la combierto a BufferedImage
                BufferedImage bimg = ImageUtils.toBufferedImage(ss.get());
                //Creo un objeto ByteArrayOutputStream
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                //Escribo el BufferedImage en el ByteArrayOutputStream con el formato png para poder obtener el peso de la imagen
                ImageIO.write(bimg, "png", out);
                //Envio una cabecera con el codigo 200 (OK) y el peso de la imagen al cliente
                he.sendResponseHeaders(200, out.size());
                //Obtengo el OutputStream para poder enviar la imagen al cliente
                OutputStream os = he.getResponseBody();
                //Escribo la BufferedImage al cliente.
                ImageIO.write(bimg, "png", os);
                //cierro la conexión
                os.close();
            } catch (AWTException ex) {
                Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if(he.getHttpContext().getPath().equals("/click")) {
            try {
                //Obtenemos los parametros
                Map<String, Object> params = (Map<String, Object>) he.getAttribute("parameters");
                //tomamos la posicion X e Y obtenidas de los parametros
                int x=  Integer.parseInt(params.get("x").toString());
                int y= Integer.parseInt(params.get("y").toString());
                //Creamos un Objeto PCControl
                PCControl control = new PCControl();
                //llamamos al metodo click y le pasamos como parametro un punto con las coordenadas obtenidas por parametros
                control.click(new Point(x, y));

                System.out.println("[INFO] ["+he.getRemoteAddress()+"] Click <x:" + params.get("x") + " y:" + params.get("y")+">");
                //## Enviamos cabeceras para evitar el cache en los navegadores
                he.getResponseHeaders().add("Pragma", "no-cache");
                he.getResponseHeaders().add("Cache-Control", "no-cache");
                //## Enviamos todo al cliente
                he.getResponseBody().flush();
                //## Cerramos la conexion
                he.close();
            } catch (AWTException ex) {
                Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

Con eso ya tenemos listo nuestro servidor. que tendrá dos “funcionalidades” que se accederán por:

http://ipservidor:puerto/get

Obtiene una imagen del escritorio

http://ipservidor:puerto/click?x={posX}&y={posY}

Hace un click en un punto dado

Ahora crearemos el Cliente que accederá al servidor, Para eso usaremos JQuery y la tecnología AJAX

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
		<!-- Agregamos el framework JQuery -->
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
		<script type="text/javascript">
			/*
				Declaramos una variable con la ip del servidor y el puerto que está escuchando
				Ejemplo:
					var uri = "127.0.0.1:80";
			*/
			var uri = "ipservidor:80";
			/*
				Al cargar toda la pagina ejecuto el codigo
			*/
			$(document).ready(function() {
				/*
					Agrego al elemento con la id box un elemento html "img"
				*/
				$('#box').html(
					/*
						agrego una imagen llamando al servidor (ScreenShot)
					*/
					$('<img>').attr('id','desktop').attr('src','http://'+uri+'/get').mousemove(function(e) {
						/*
							Agrego un evento javascript a la imagen, al mover el mouse sobre ella me muestra la posicion en un div con id "status"
						*/
						var mouseX = e.pageX - $(this).attr('offsetLeft');
                        var mouseY = e.pageY - $(this).attr('offsetTop');
						$('#status').html(mouseX+', '+ mouseY+ ' %, %'+$(this).width());
					}).click(function(e) {
						/*
							Agrego un evento javascript a la imagen, al clickear la imagen se conecte via AJAX al servidor
							y le pase las coordenadas del click que hice en la imagen para que el servidor ejecute un click en la maquina
						*/
						var imgObj = $(this);
						var mouseX = e.pageX - $(this).attr('offsetLeft');
                        var mouseY = e.pageY - $(this).attr('offsetTop');
						$.ajax({
							url: 'http://'+uri+'/click?x='+mouseX+'&y='+mouseY,
							success: function(data) {
								$('#desktop').attr('src','http://'+uri+'/get?r='+Math.random());
								console.log('sus');
							},
							error: function(XMLHttpRequest, textStatus, errorThrown) {
								$('#desktop').attr('src','http://'+uri+'/get?r='+Math.random());
								console.log('err');
							}
						});
					})
				);
			});
		</script>
	</head>
	<body>
		<span id="status"></span>
		<div id="box"></div>
	</body>
</html>

Con eso ya podemos acceder remotamente ha algún PC vía web.

Esto es solo una idea ustedes pueden modificarlo y arreglarlo a su gusto. Se podria implementar para escribir desde la web, refrescar cada X segundos, etc.

Codigo FuenteServTest.EstebanFuentealba.rar

Para correr el servidor en CMD o Terminal escriban

java -jar ServTest.jar 80

ServTest.jar se encuentra en la carpeta dist

Espero que les sirva, Saludos!

Categorías:Proyectos Etiquetas: , , ,
  1. mayo 16, 2010 a las 1:00 am

    Questo articolo e veramente interessante

  2. Juan Carlos
    septiembre 14, 2010 a las 8:57 am

    Buenas, me interesa mucho el tema de programar un control remoto via web para mis clientes, de tal forma que el cliente pinche en un enlace de mi página dandome el correspondiente acceso para poder controlar su pc y, asi, poder ayudarle con el problema. la verdad es que no sabia por donde empezar.

    He estado leyendo tu artículo y es muy interesante, con el pequeño inconveniente que estoy algo “pegado” (bueno bastante) en el tema, la verdad. He descargado el código fuente que pones pero no se como implementarlo. Si me pudieras ayudar, o darme los primeros pasos….. sería de gran ayuda.

    Espero no pedir demasiado pero me encanta aprender cosas nuevas pero siempre se necesita un pie para empezar. Muchas gracias y espero tu respuesta

  3. Diego
    diciembre 14, 2011 a las 9:52 pm

    Amigo muy buen proyecto, pero tengo problemas para descargarme el codigo. Podrias ayudarme.

  4. Janneth
    diciembre 21, 2011 a las 8:18 pm

    Muy buena tu aplicación…por favor me puedes ayudar con el código fuente

  5. A. Manuel Durán
    febrero 27, 2012 a las 12:29 pm

    Buenas a tod@.
    Como en el caso de Juan Carlos, yo también estoy intentando desarrollar una herramienta web a través de la cual poder ofrecer soporte a los clientes que nos lo soliciten y en caso preciso poder coger el control de su equipo para temas de pequeña índole que se puedan solucionar sin necesidad de un desplazamiento hasta el local del cliente.

    Como JC tampoco tenía ni idea por donde empezar, y no encuentro mucha información al respecto. Esta entrada de blog me parece un muy buen punto de partida. estoy escribiendo linea por linea el código que mencionas para comprender lo y así poder trabajar bien con el y extenderlo si fuese funcional.

    Para hacer las primeras pruebas con tu código necesitaría todas las dependencias sobre todo las que cuelgan de “servtest” que supongo que será una librería personal tuya.
    Tampoco consigo averiguar la dependencia de “ParameterFilter()”.

    Supongo que tu librería está incluida en el paquete que colocaste para descarga, pero el problema es que la descarga no funciona.

    Te agradecería mucho si pudieras volver a colocar para descarga el paquete con el código fuente.

    Un saludo! y mis felicitaciones por la entrada!!!

  6. Airi
    noviembre 19, 2012 a las 3:42 pm

    Hola a todos, navegando me he encontrado con este gran proyecto y me gustaría saber si habeís logrado implementarlo. Un saludo a todos.

  7. marzo 19, 2014 a las 4:38 pm

    me da este error Error: Could not find or load main class servtest.Main

  1. agosto 16, 2010 a las 4:51 pm

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: