65.9K
CodeProject 正在变化。 阅读更多。
Home

Java 远程桌面管理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (44投票s)

2009年5月1日

CPOL

4分钟阅读

viewsIcon

279602

downloadIcon

37043

远程控制和查看另一台计算机

实际客户端桌面

client_screen_small.JPG

已连接客户端桌面的远程图像

connected_client_small.JPG

介绍 

该程序允许任何计算机远程控制其他 PC。   

程序功能

  • 查看远程桌面
  • 鼠标移动控制
  • 鼠标按键控制
  • 键盘控制

背景  

该项目最大的挑战之一是找到一种移动鼠标指针、模拟按键和捕获屏幕的方法。花了一些时间后,我发现了一个很棒的类——Robot 类,它完成了我需要的一切。

此外,使用序列化将屏幕截图从客户端发送到服务器,并发送服务器事件(如鼠标移动、按键、释放按键)  帮助我编写了干净简单的代码,而不是通过网络以原始数据格式发送图像和事件。

Robot 类方法 

  • mouseMove - 将鼠标指针移动到以像素为单位指定的绝对屏幕坐标集
  • mousePress - 按下鼠标的一个按钮
  • mouseRelease - 释放鼠标的一个按钮
  • keyPress - 按下键盘上的指定按键
  • keyRelease - 释放键盘上的指定按键
  • createScreenCapture - 截屏  

程序部分   

1. RemoteServer 

这是服务器部分,它等待客户端连接,对于每个连接的客户端,都会出现一个显示当前客户端屏幕的新窗口。当您将鼠标移到窗口上时,这会导致在客户端移动鼠标。当您在窗口处于焦点时,单击鼠标左键/右键或输入一个键时,也会发生同样的情况。

2. RemoteClient  

这是客户端,其核心功能是每隔预定义的时间间隔发送客户端桌面的屏幕截图。它还接收服务器命令,例如“移动鼠标命令”,然后执行客户端 PC 上的命令。  

使用代码 

要运行该程序,您需要在两台不同的 PC 上下载 RemoteServer_source.zip 和 RemoteClient_source.zip ,然后解压。在一台 PC(例如 PC1)上,使用以下命令运行位于 dist 文件夹下的 RemoteServer.jar: 

>> java -jar  RemoteServer.jar 

系统会要求您输入服务器监听的端口号,输入任何大于 1024 的端口号,例如 5000。  

在另一台 PC(例如 PC2)上,使用以下命令执行 RemoteClient.jar:  

>> java -jar RemoteClient.jar  

系统会要求您输入服务器 IP,输入 PC1 的 IP 地址,然后会要求您输入端口号,输入您上面输入的相同端口,例如 5000。 

现在,在 PC1 上,您可以完全控制 PC2,包括移动鼠标、单击鼠标、输入按键、查看 PC2 桌面等。  

代码结构   

RemoteServer

ServerInitiator 类

这是入口类,它监听服务器端口并等待客户端连接。此外,它还创建程序 GUI 的一个重要部分。

ClientHandler 类 

对于每个连接的客户端,都有一个此类对象。它为每个客户端显示一个 InternalFrame 并接收客户端的屏幕尺寸。

ClientScreenReciever 类 

接收来自客户端的捕获屏幕,然后显示它。

ClientCommandsSender 类

它监听服务器命令,然后将它们发送到客户端。服务器命令包括鼠标移动、按键、鼠标单击等。

EnumCommands 类

定义常量,用于表示服务器命令。

RemoteClient   

ClientInitiator 类 

这是启动客户端实例的入口类。它建立与服务器的连接并创建客户端 GUI。

ScreenSpyer 类  

定期捕获屏幕并将其发送到服务器。

ServerDelegate 类   

接收服务器命令并在客户端 PC 上执行它们。

EnumCommands 类  

定义常量,用于表示服务器命令。  

代码片段

1) RemoteClient  

连接到服务器 
 System.out.println("Connecting to server ..........");
 socket = new Socket(ip, port);
 System.out.println("Connection Established.");  
定期捕获桌面屏幕然后发送到服务器  

ScreenSpyer 类中,使用 Robot 类中的 createScreenCapture 方法捕获 Screen,它接受一个 Rectangle 对象,该对象包含屏幕尺寸。如果我们尝试直接通过序列化发送图像对象,它会失败,因为 Image 对象没有实现 Serializable 接口。这就是为什么我们必须像下面这样使用 ImageIcon 类来包装它。

while(continueLoop){
            //Capture screen
            BufferedImage image = robot.createScreenCapture(rectangle);
            /* I have to wrap BufferedImage with ImageIcon because 
	     * BufferedImage class does not implement Serializable interface
             */
            ImageIcon imageIcon = new ImageIcon(image);

            //Send captured screen to the server
            try {
                System.out.println("before sending image");
                oos.writeObject(imageIcon);
                oos.reset(); //Clear ObjectOutputStream cache
                System.out.println("New screenshot sent");
            } catch (IOException ex) {
               ex.printStackTrace();
            }

            //wait for 100ms to reduce network traffic
            try{
                Thread.sleep(100);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
接收服务器事件然后调用 Robot 类方法来执行这些事件 
while(continueLoop){
                //receive commands and respond accordingly
                System.out.println("Waiting for command");
                int command = scanner.nextInt();
                System.out.println("New command: " + command);
                switch(command){
                    case -1:
                        robot.mousePress(scanner.nextInt());
                    break;
                    case -2:
                        robot.mouseRelease(scanner.nextInt());
                    break;
                    case -3:
                        robot.keyPress(scanner.nextInt());
                    break;
                    case -4:
                        robot.keyRelease(scanner.nextInt());
                    break;
                    case -5:
                        robot.mouseMove(scanner.nextInt(), scanner.nextInt());
                    break;
                }
            }

2) RemoteServer

等待客户端连接 
//Listen to server port and accept clients connections
            while(true){
                Socket client = sc.accept();
                System.out.println("New client Connected to the server");
                //Per each client create a ClientHandler
                new ClientHandler(client,desktop);
            }
接收客户端桌面屏幕截图并显示它们
 while(continueLoop){
 //Receive client screenshot and resize it to the current panel size
  ImageIcon imageIcon = (ImageIcon) cObjectInputStream.readObject();
  System.out.println("New image received");
  Image image = imageIcon.getImage();
  image = image.getScaledInstance
	(cPanel.getWidth(),cPanel.getHeight(),Image.SCALE_FAST);
  //Draw the received screenshot
  Graphics graphics = cPanel.getGraphics();
  graphics.drawImage(image, 0, 0, cPanel.getWidth(),cPanel.getHeight(),cPanel);
}
处理鼠标和键盘事件然后将它们发送到客户端程序进行模拟 

ClientCommandsSender 类中,当鼠标移动时,x 和 y 值会发送到客户端,但我们必须考虑到客户端屏幕尺寸和服务器面板尺寸之间的差异,这就是为什么我们必须乘以一个特定的因子,如下面的代码所示: 

   public void mouseMoved(MouseEvent e) {
        double xScale = clientScreenDim.getWidth()/cPanel.getWidth();
        System.out.println("xScale: " + xScale);
        double yScale = clientScreenDim.getHeight()/cPanel.getHeight();
        System.out.println("yScale: " + yScale);
        System.out.println("Mouse Moved");
        writer.println(EnumCommands.MOVE_MOUSE.getAbbrev());
        writer.println((int)(e.getX() * xScale));
        writer.println((int)(e.getY() * yScale));
        writer.flush();
    }

    public void mousePressed(MouseEvent e) {
        System.out.println("Mouse Pressed");
        writer.println(EnumCommands.PRESS_MOUSE.getAbbrev());
        int button = e.getButton();
        int xButton = 16;
        if (button == 3) {
            xButton = 4;
        }
        writer.println(xButton);
        writer.flush();
    }

    public void mouseReleased(MouseEvent e) {
        System.out.println("Mouse Released");
        writer.println(EnumCommands.RELEASE_MOUSE.getAbbrev());
        int button = e.getButton();
        int xButton = 16;
        if (button == 3) {
            xButton = 4;
        }
        writer.println(xButton);
        writer.flush();
    }


    public void keyPressed(KeyEvent e) {
        System.out.println("Key Pressed");
        writer.println(EnumCommands.PRESS_KEY.getAbbrev());
        writer.println(e.getKeyCode());
        writer.flush();
    }

    public void keyReleased(KeyEvent e) {
        System.out.println("Mouse Released");
        writer.println(EnumCommands.RELEASE_KEY.getAbbrev());
        writer.println(e.getKeyCode());
        writer.flush();
    }
© . All rights reserved.