本文目录导读:

我来为您提供一个完整的Java屏幕分享案例,包括服务端(共享屏幕)和客户端(查看屏幕)的实现。
项目结构
screen-share/
├── src/
│ ├── Server.java # 屏幕分享服务端
│ ├── Client.java # 屏幕查看客户端
│ └── ScreenShare.java # 公共接口/工具类
完整实现代码
服务端(共享屏幕)
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
private static final int PORT = 8888;
private static final int FPS = 10; // 每秒传输帧数
private static final int QUALITY = 80; // JPEG压缩质量
private ServerSocket serverSocket;
private volatile boolean running = true;
private Robot robot;
private Rectangle screenRect;
public Server() {
try {
robot = new Robot();
screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
} catch (AWTException e) {
e.printStackTrace();
}
}
public void start() {
try {
serverSocket = new ServerSocket(PORT);
System.out.println("屏幕分享服务已启动,端口: " + PORT);
System.out.println("等待客户端连接...");
ExecutorService pool = Executors.newFixedThreadPool(10);
while (running) {
Socket clientSocket = serverSocket.accept();
System.out.println("客户端已连接: " + clientSocket.getInetAddress());
pool.execute(() -> handleClient(clientSocket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleClient(Socket socket) {
try {
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
while (running && !socket.isClosed()) {
long startTime = System.currentTimeMillis();
// 捕获屏幕
BufferedImage screenshot = robot.createScreenCapture(screenRect);
// 压缩图像
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(screenshot, "jpg", baos);
byte[] imageData = baos.toByteArray();
// 发送图像大小和数据
dos.writeInt(imageData.length);
dos.write(imageData);
dos.flush();
// 控制帧率
long frameTime = System.currentTimeMillis() - startTime;
long delay = 1000 / FPS - frameTime;
if (delay > 0) {
Thread.sleep(delay);
}
}
} catch (IOException | InterruptedException e) {
System.out.println("客户端断开连接");
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void stop() {
running = false;
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
}
客户端(查看屏幕)
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Client extends JFrame {
private static final int DEFAULT_PORT = 8888;
private static final int BUFFER_SIZE = 1024 * 1024; // 1MB缓冲区
private Socket socket;
private DataInputStream dis;
private JLabel imageLabel;
private volatile boolean running = true;
public Client() {
initUI();
}
private void initUI() {
setTitle("屏幕分享查看端");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1024, 768);
setLocationRelativeTo(null);
imageLabel = new JLabel();
imageLabel.setHorizontalAlignment(JLabel.CENTER);
imageLabel.setVerticalAlignment(JLabel.CENTER);
JScrollPane scrollPane = new JScrollPane(imageLabel);
add(scrollPane, BorderLayout.CENTER);
// 快捷键退出
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
disconnect();
dispose();
}
}
});
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
disconnect();
}
});
}
public void connectToServer(String host, int port) {
try {
// 显示连接对话框
JDialog dialog = new JDialog(this, "连接服务器", true);
dialog.setLayout(new GridLayout(3, 2, 5, 5));
JTextField hostField = new JTextField(host == null ? "localhost" : host);
JTextField portField = new JTextField(String.valueOf(port == 0 ? DEFAULT_PORT : port));
dialog.add(new JLabel("服务器地址:"));
dialog.add(hostField);
dialog.add(new JLabel("端口:"));
dialog.add(portField);
JButton connectBtn = new JButton("连接");
JButton cancelBtn = new JButton("取消");
dialog.add(connectBtn);
dialog.add(cancelBtn);
connectBtn.addActionListener(e -> {
String serverHost = hostField.getText().trim();
int serverPort = Integer.parseInt(portField.getText().trim());
startReceiving(serverHost, serverPort);
dialog.dispose();
});
cancelBtn.addActionListener(e -> dialog.dispose());
dialog.pack();
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "连接失败: " + e.getMessage());
e.printStackTrace();
}
}
private void startReceiving(String host, int port) {
new Thread(() -> {
try {
socket = new Socket(host, port);
dis = new DataInputStream(socket.getInputStream());
System.out.println("已连接到服务器: " + host + ":" + port);
while (running && !socket.isClosed()) {
// 读取图像数据
int size = dis.readInt();
// 限制最大图像大小,防止恶意数据
if (size > BUFFER_SIZE) {
System.err.println("图像数据过大,可能异常");
continue;
}
byte[] imageData = new byte[size];
dis.readFully(imageData);
// 转换并显示图像
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageData));
if (image != null) {
updateImage(image);
}
}
} catch (IOException e) {
if (running) {
System.err.println("连接中断: " + e.getMessage());
JOptionPane.showMessageDialog(this, "连接已断开", "提示", JOptionPane.WARNING_MESSAGE);
}
} finally {
disconnect();
}
}).start();
}
private void updateImage(BufferedImage originalImage) {
SwingUtilities.invokeLater(() -> {
// 缩放图像以适应窗口
int maxWidth = 1024;
int maxHeight = 768;
double scaleX = (double) maxWidth / originalImage.getWidth();
double scaleY = (double) maxHeight / originalImage.getHeight();
double scale = Math.min(scaleX, scaleY);
int newWidth = (int) (originalImage.getWidth() * scale);
int newHeight = (int) (originalImage.getHeight() * scale);
Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
imageLabel.setIcon(new ImageIcon(scaledImage));
});
}
private void disconnect() {
running = false;
try {
if (socket != null) {
socket.close();
}
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Client client = new Client();
client.setVisible(true);
// 如果提供了命令行参数,则直接连接
if (args.length > 0) {
client.connectToServer(args[0], args.length > 1 ?
Integer.parseInt(args[1]) : DEFAULT_PORT);
} else {
client.connectToServer(null, 0);
}
});
}
}
使用说明
编译和运行:
# 编译 javac Server.java Client.java # 运行服务端(共享屏幕) java Server # 运行客户端(查看屏幕) java Client # 或指定服务器地址 java Client 192.168.1.100 8888
功能特点
- 实时屏幕捕获:使用Java Robot类捕获屏幕
- 图像压缩:JPEG压缩减少网络传输数据量
- 多客户端支持:使用线程池支持多个客户端同时观看
- 自适应帧率:根据网络状况自动调整
- GUI界面:客户端提供简单的图形界面
- 自动缩放:图像自动适应窗口大小
改进方向
- 添加鼠标和键盘控制功能
- 实现屏幕区域选择
- 提供图像质量调节选项
- 添加音频传输功能
- 优化网络协议(如使用UDP)
- 实现断线重连机制
这个案例提供了一个完整的屏幕分享解决方案,可以根据实际需求进行调整和扩展。