Java屏幕分享案例

wen java案例 3

本文目录导读:

Java屏幕分享案例

  1. 项目结构
  2. 完整实现代码

我来为您提供一个完整的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

功能特点

  1. 实时屏幕捕获:使用Java Robot类捕获屏幕
  2. 图像压缩:JPEG压缩减少网络传输数据量
  3. 多客户端支持:使用线程池支持多个客户端同时观看
  4. 自适应帧率:根据网络状况自动调整
  5. GUI界面:客户端提供简单的图形界面
  6. 自动缩放:图像自动适应窗口大小

改进方向

  • 添加鼠标和键盘控制功能
  • 实现屏幕区域选择
  • 提供图像质量调节选项
  • 添加音频传输功能
  • 优化网络协议(如使用UDP)
  • 实现断线重连机制

这个案例提供了一个完整的屏幕分享解决方案,可以根据实际需求进行调整和扩展。

抱歉,评论功能暂时关闭!