远程桌面控制程序

在当今的数字化时代,远程工作和协作变得越来越普遍。为了满足这种需求,开发了一种允许计算机之间远程控制的程序。这种程序不仅可以提高工作效率,还可以在需要时提供技术支持。本文将详细介绍该程序的主要功能、实现方式以及如何使用它。

程序特点

该远程桌面控制程序具有以下特点:

  • 查看远程桌面:用户可以查看连接到服务器的客户端的桌面。
  • 鼠标移动控制:用户可以通过服务器端控制客户端的鼠标指针。
  • 鼠标按钮控制:用户可以远程点击客户端的鼠标左键或右键。
  • 键盘控制:用户可以远程输入键盘命令到客户端。

在开发这个项目时,最大的挑战之一是如何实现鼠标指针的移动、模拟键盘敲击以及屏幕捕获。经过一段时间的研究,发现了一个名为Robot的类,它能够满足所有的需求。此外,使用序列化来发送客户端屏幕截图到服务器,以及发送服务器事件(如鼠标移动、按键按下、按键释放)帮助编写了清晰而简单的代码,而不是以原始数据格式通过网络发送图像和事件。

Robot类方法

Robot类提供了以下方法:

  • mouseMove:将鼠标指针移动到屏幕上的指定坐标。
  • mousePress:按下鼠标上的一个按钮。
  • mouseRelease:释放鼠标上的一个按钮。
  • keyPress:按下键盘上的一个键。
  • keyRelease:释放键盘上的一个键。
  • createScreenCapture:捕获屏幕截图。

程序组成部分

程序由以下部分组成:

  • RemoteServer:服务器端,等待客户端连接,并为每个连接的客户端显示当前客户端屏幕的新框架。当在框架上移动鼠标时,这会导致在客户端移动鼠标。当点击鼠标按钮或在框架处于焦点时键入键时,也会发生同样的情况。
  • RemoteClient:客户端,其核心功能是定期发送客户端桌面的屏幕截图。它还接收服务器命令,然后在客户端PC上执行该命令。

使用代码

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

java -jar RemoteServer.jar

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

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

java -jar RemoteClient.jar

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

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

编码结构

以下是RemoteServer和RemoteClient的代码结构:

  • RemoteServer
    • ServerInitiator类:这是入口类,它监听服务器端口并等待客户端连接。它还创建程序GUI的重要部分。
    • ClientHandler类:对于每个连接的客户端,都有一个此类的对象。它显示每个客户端的InternalFrame,并接收客户端的屏幕尺寸。
    • ClientScreenReciever类:接收客户端捕获的屏幕,然后显示它。
    • ClientCommandsSender类:它监听服务器命令,然后将它们发送到客户端。服务器命令包括鼠标移动、键盘敲击、鼠标点击等。
    • EnumCommands类:定义用于表示服务器命令的常量。
  • RemoteClient
    • ClientInitiator类:这是启动客户端实例的入口类。它建立与服务器的连接并创建客户端GUI。
    • ScreenSpyer类:定期捕获屏幕并将其发送到服务器。
    • ServerDelegate类:接收服务器命令并在客户端PC上执行它们。
    • EnumCommands类:定义用于表示服务器命令的常量。

代码片段

  • RemoteClient
    • 连接到服务器:
    • System.out.println("Connecting to server .........."); socket = new Socket(ip, port); System.out.println("Connection Established.");
    • 定期捕获桌面屏幕然后发送到服务器:
    • 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; } }
  • 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); }
    • 处理鼠标和键盘事件然后将它们发送到客户端程序以模拟它们:
    • 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(); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485