Java 远程桌面管理






4.96/5 (44投票s)
远程控制和查看另一台计算机
实际客户端桌面
已连接客户端桌面的远程图像
介绍
该程序允许任何计算机远程控制其他 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();
}