首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現螢幕廣播與鼠標同步控制的雙通道 Socket 方案

     編輯:Java 相關知識

架構設計

採用雙 Socket 通道分離關注點:

  • 通道 1 (Port 8002):服務端推送螢幕截圖(JPG + ZIP 壓縮)
  • 通道 2 (Port 8001):服務端推送鼠標座標(文本協議 Movemouse,x,y)

客戶端並行接收兩個通道數據,分別在 Swing 界面顯示圖片、用 Robot.mouseMove 同步鼠標。

服務端核心代碼

主啟動類

public class BroadCastServer {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        pool.execute(new SendScreenImg());   // 截圖發送線程
        pool.execute(new SendMouseMessage()); // 鼠標發送線程
        System.out.println("廣播服務已啟動");
    }
}

截圖發送線程 (SendScreenImg)

public class SendScreenImg extends Thread {
    private final int PORT = 8002;
    private final ServerSocket server;
    private final Robot robot;
    private final Rectangle screenRect;

    public SendScreenImg() throws AWTException, IOException {
        server = new ServerSocket(PORT);
        robot = new Robot();
        Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
        screenRect = new Rectangle(size);
    }

    @Override
    public void run() {
        while (true) {
            try (Socket client = server.accept();
                 ZipOutputStream zos = new ZipOutputStream(new DataOutputStream(client.getOutputStream()))) {
                zos.setLevel(9);
                BufferedImage img = robot.createScreenCapture(screenRect);
                zos.putNextEntry(new ZipEntry("screen.jpg"));
                ImageIO.write(img, "jpg", zos);
                zos.closeEntry();
            } catch (IOException e) {
                System.err.println("截圖通道異常: " + e.getMessage());
            }
        }
    }
}

鼠標發送線程 (SendMouseMessage)

public class SendMouseMessage extends Thread {
    private final int PORT = 8001;
    private final ServerSocket server;

    public SendMouseMessage() throws IOException {
        server = new ServerSocket(PORT);
    }

    @Override
    public void run() {
        while (true) {
            try (Socket client = server.accept();
                 DataOutputStream out = new DataOutputStream(client.getOutputStream())) {
                Point pt = MouseInfo.getPointerInfo().getLocation();
                String msg = "Movemouse," + pt.x + "," + pt.y;
                out.write(msg.getBytes());
                out.flush();
            } catch (IOException e) {
                System.err.println("鼠標通道斷開: " + e.getMessage());
            }
        }
    }
}

客戶端核心代碼

主啟動類

public class BroadcastClient {
    private static final String SERVER_IP = "192.168.1.100"; // 替換為服務端 IP

    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        pool.execute(new ReceiveImages(SERVER_IP));
        pool.execute(new OperateMouse(SERVER_IP));
    }
}

接收圖片線程 (ReceiveImages)

public class ReceiveImages extends Thread {
    private final String ip;
    private final JFrame frame = new JFrame("遠程桌面");
    private final JLabel imgLabel = new JLabel();

    public ReceiveImages(String ip) {
        this.ip = ip;
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(imgLabel);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    @Override
    public void run() {
        while (frame.isDisplayable()) {
            try (Socket socket = new Socket(ip, 8002);
                 ZipInputStream zis = new ZipInputStream(socket.getInputStream())) {
                zis.getNextEntry();
                Image img = ImageIO.read(zis);
                if (img != null) {
                    SwingUtilities.invokeLater(() -> {
                        imgLabel.setIcon(new ImageIcon(img));
                        frame.pack();
                    });
                }
                Thread.sleep(50); // 幀率控制 ~20fps
            } catch (Exception e) {
                System.err.println("圖片接收異常: " + e.getMessage());
                try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
            }
        }
    }
}

鼠標同步線程 (OperateMouse)

public class OperateMouse extends Thread {
    private final String ip;
    private final Robot robot;

    public OperateMouse(String ip) throws AWTException {
        this.ip = ip;
        this.robot = new Robot();
    }

    @Override
    public void run() {
        while (true) {
            try (Socket socket = new Socket(ip, 8001);
                 DataInputStream in = new DataInputStream(socket.getInputStream())) {
                StringBuilder sb = new StringBuilder();
                int b;
                while ((b = in.read()) != -1) sb.append((char) b);
                String msg = sb.toString().trim();
                if (msg.startsWith("Movemouse")) {
                    String[] parts = msg.split(",");
                    if (parts.length == 3) {
                        int x = Integer.parseInt(parts[1]);
                        int y = Integer.parseInt(parts[2]);
                        robot.mouseMove(x, y);
                    }
                }
            } catch (IOException e) {
                System.err.println("鼠標同步斷開: " + e.getMessage());
                try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
            }
        }
    }
}

關鍵技術點總結

局限與改進方向

  • 鼠標座標與螢幕分辨率綁定,多顯示器/縮放環境需座標轉換。
  • 未實現鼠標點擊、鍵盤事件傳輸,協議可擴展為 Click,x,y,button、Key,code,pressed。
  • 生產環境建議加入 TLS 加密、身份驗證、幀差異編碼(如 H.264/VP8)以提升性能與安全性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
點說明
Robot 類同時用於截圖 (createScreenCapture) 與鼠標控制 (mouseMove)
ZIP 壓縮截圖傳輸前壓縮,顯著降低帶寬(設級別 9 最大壓縮)
線程池固定 2 線程隔離兩通道,避免相互阻塞
Swing 線程安全UI 更新必須在 EDT 執行,使用 SwingUtilities.invokeLater
異常重連客戶端捕獲異常後 sleep 重試,實現斷線自動重連