Java远程屏幕监控案例

 

该案例主要分为两个类文件,Server及其中的内部类,Client及其中的内部类。

大家可以参考。

如对Java远控比较感兴趣可以到我的网站上看一下

我们最近用Java开发的一款“黑天鹅远控”软件,并且为开源软件。

该案例为该软件中的一个功能点的源代码,并且已经整理成为单独的完善的案例。

我们的官方网站网址: http://www.blackswansoft.com/

你可以在该网站上下载 “黑天鹅远控”软件。网站上发布了更多的java热点技术,欢迎大家参考。

QQ:1037729010

Email: blackswansoft@163.com

 

 

/**

 *服务端代码

 *

 */

import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.imageio.ImageIO;

public class Server{
 public static void main(String args[]) {
  SendScreenImg sender=new SendScreenImg();
  sender.changeServerPort(30009);//此处可以修改服务端口
  new Thread(sender).start();//打开图像传输服务
  OperateWindow operate=new OperateWindow();
//  operate.changeServerPort(30010);//此处可以修改服务端口
  new Thread(operate).start();//打开主机操控服务
  
  //***** 当然 服务器端的端口修改是随时都可以操作的 它实际上是关闭以前的端口 再开启一个新端口 *****//
 }
}

/**
 * @author LanXJ @doctime 2010-7-8
 * 开启一个设定端口的服务,该服务用于向客户端传送主机的屏幕信息,实现客户端对服务器端主机的监控
 * 实例化线程类后默认打开DEFAULT_SERVER_PORT=30011 端口实现监听
 * 可以通过changeServerPort改变监听端口,也可以通过getServerPort来查询当前监听端口
 */
class SendScreenImg implements Runnable{

 public static final int DEFAULT_SERVER_PORT=30011;
 private int serverPort;
 private Robot robot;
 private ServerSocket serverSocket;
 private Rectangle rect;
 private Dimension screen;
 private BufferedImage img;
 private Socket socket;
 private ZipOutputStream zip;

 public SendScreenImg() {
  this.serverPort=SendScreenImg.DEFAULT_SERVER_PORT;

  try {
   serverSocket = new ServerSocket(this.serverPort);
   serverSocket.setSoTimeout(86400000);
  } catch (IOException e1) {
   e1.printStackTrace();
  }

  try {
   robot = new Robot();
  } catch (AWTException e) {
   e.printStackTrace();
  }
  screen = Toolkit.getDefaultToolkit().getScreenSize();
  rect = new Rectangle(screen);

 }
 public void changeServerPort(int serverPort){
  if(this.serverPort==serverPort)return;
  this.serverPort=serverPort;
  try {
   this.serverSocket.close();
  } catch (Exception e) {}
  try {
   serverSocket = new ServerSocket(this.serverPort);
   serverSocket.setSoTimeout(86400000);
  } catch (IOException e1) {
   e1.printStackTrace();
  }
 }
 public int getServerPort(){
  return this.serverPort;
 }

 public void run() {
  while (true) {
             try {
              System.out.println("等待接收截屏信息");
                 socket = serverSocket.accept();
                 zip = new ZipOutputStream(new DataOutputStream(socket.getOutputStream()));
                 zip.setLevel(9);//为后续的 DEFLATED 条目设置压缩级别 压缩级别 (0-9)
                 try {
                  img = robot.createScreenCapture(rect);
                     zip.putNextEntry(new ZipEntry("test.jpg"));
                     ImageIO.write(img, "jpg", zip);
                     if(zip!=null)zip.close();
                     System.out.println("被控端:connect");
                 } catch (IOException ioe) {
                     System.out.println("被控端:disconnect");
                 }
             } catch (IOException ioe) {
              System.out.println("错误1");
             } finally {
                 if (socket != null) {
                     try {
                         socket.close();
                     } catch (IOException e) {
                     }
                 }
             }
         }
 }
}

/**
 * @author LanXJ @doctime 2010-7-8
 * 开启一个设定端口的服务,该服务用于接受客户端传来的操作字符串,实现对服务器端主机的操控
 * 实例化线程类后默认打开DEFAULT_SERVER_PORT=30012 端口实现监听
 * 可以通过changeServerPort改变监听端口,也可以通过getServerPort来查询当前监听端口
 */
class OperateWindow implements Runnable {
 public static final int DEFAULT_SERVER_PORT=30012;
 private int serverPort;
 private ServerSocket serverSocket;
 private Robot robot;
 public OperateWindow() {
  this.serverPort=OperateWindow.DEFAULT_SERVER_PORT;
  try {
   this.serverSocket = new ServerSocket(this.serverPort);
   this.serverSocket.setSoTimeout(86400000);
  } catch (IOException e) {
   e.printStackTrace();
  }
  try {
   robot = new Robot();
  } catch (AWTException e) {
   e.printStackTrace();
  }
 }
 public void changeServerPort(int serverPort){
  if(this.serverPort==serverPort)return;
  this.serverPort=serverPort;
  try {
   this.serverSocket.close();
  } catch (Exception e) {}
  try {
   this.serverSocket = new ServerSocket(this.serverPort);
   this.serverSocket.setSoTimeout(86400000);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 public int getServerPort(){
  return this.serverPort;
 }

 public void run() {
  while (true) {
   try {
    Socket socket = serverSocket.accept();
    //读取操作信息:120,200,InputEvent.BUTTON1_DOWN_MASK 全部是int类型
    InputStream is = socket.getInputStream();
    int r;
    String info = "";
    while ((r = is.read()) != -1) {
     info += "" + (char) r;
    }
    System.out.println(info);
    is.close();
    if (info != null) {
     String s[] = info.trim().split(",");
     if ("mouseClicked".equals(s[0].trim())) {//operateStr Model: mouseClicked,x,y,type 
      //由于加上单击事件后,鼠标按下并快速抬起 就设计到按下、抬起、单击 三个事件,将单击变为了双击 不合乎规范  所以 服务端并没有实现单击事件的监听,这里保留 不坐修改
      int type = Integer.parseInt(s[s.length - 1].trim());
      if (s.length == 4) {
       int x = Integer.parseInt(s[1].trim());
       int y = Integer.parseInt(s[2].trim());
       robot.mouseMove(x, y);
       robot.mousePress(type);
       robot.mouseRelease(type);
       System.out.println("ClientINFO:MOUSE move to "+x+","+y+" AND execute TYPE IS click "+type);
      }
     }else if("mousePressed".equals(s[0].trim())){//operateStr Model: mousePressed,x,y,type
      int type = Integer.parseInt(s[s.length - 1].trim());
      if (s.length == 4) {
       int x = Integer.parseInt(s[1].trim());
       int y = Integer.parseInt(s[2].trim());
       robot.mouseMove(x, y);
       robot.mousePress(type);
       System.out.println("ClientINFO:MOUSE move to "+x+","+y+" AND execute TYPE IS press "+type);
      }
     }else if("mouseReleased".equals(s[0].trim())){//operateStr Model: mouseReleased,x,y,type
      int type = Integer.parseInt(s[s.length - 1].trim());
      if (s.length == 4) {
       int x = Integer.parseInt(s[1].trim());
       int y = Integer.parseInt(s[2].trim());
       robot.mouseMove(x, y);
       robot.mouseRelease(type);
       System.out.println("ClientINFO:MOUSE move to "+x+","+y+" AND execute TYPE IS release  "+type);
      }
     }else if("mouseDragged".equals(s[0].trim())){//operateStr Model: mouseDragged,x,y,type
      if (s.length == 4) {
       int x = Integer.parseInt(s[1].trim());
       int y = Integer.parseInt(s[2].trim());
       robot.mouseMove(x, y);
       System.out.println("ClientINFO:MOUSE move to "+x+","+y );
      }
     }else if("mouseMoved".equals(s[0].trim())){
      if (s.length == 3) {
       int x = Integer.parseInt(s[1].trim());
       int y = Integer.parseInt(s[2].trim());
       robot.mouseMove(x, y);
       System.out.println("ClientINFO:MOUSE move to "+x+","+y);
      }
     }else if("keyPress".equals(s[0].trim())){
      if(s.length==2){
       int keycode=Integer.parseInt(s[1]);
       robot.keyPress(keycode);
      }
     }else if("keyRelease".equals(s[0].trim())){
      if(s.length==2){
       int keycode=Integer.parseInt(s[1]);
       robot.keyRelease(keycode);
      }
     }else if("keyTyped".equals(s[0].trim())){
      if(s.length==2){
       int keycode=Integer.parseInt(s[1]);
       robot.keyPress(keycode);
       robot.keyRelease(keycode);
      }
     }
    }
   } catch (IOException e) {
    System.out.println("error1");
   }
  }
 }
}

 

 

/**

 *监控端代码

 *

 */

 

import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipInputStream;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Client{
 public static void main(String args[]) {

  ServerGUI sendOrder=new ServerGUI("127.0.0.1", "实时操控");//被监控电脑的ip地址
  WriteGUI catchScreen=new WriteGUI(sendOrder);
  catchScreen.changePort(30009);//现在可以修改获取主机屏幕信息要访问的端口号
  new Thread(catchScreen).start();//启动线程
 }
}

/**
 * @author LanXJ @doctime 2010-7-8
 * 访问指定端口的服务,从服务器端读取图像流,生成(刷新)管理面板
 * 默认访问的端口为DEFAULT_PORT=30011 端口,
 * 可以通过changePort来改变访问端口,也可以通过getPort查看当前访问端口
 * 实例化线程类时需要传入一个ServerGUI类型的辅助窗体对象
 */
class WriteGUI extends Thread {
 public static final int DEFAULT_PORT=30011;
 private int port;
 private ServerGUI rec;

 /**
  * @param rec 辅助窗体对象,可通过实例化获得
  */
 public WriteGUI(ServerGUI rec) {
  this.port=WriteGUI.DEFAULT_PORT;
  this.rec = rec;
 }
 public void changePort(int port){
  this.port=port;
 }
 public int getPort(){
  return this.port;
 }
 public void run() {
  while (rec.getBoo()) {
   System.out.println((System.currentTimeMillis()/1000)%24%60);
   Socket socket = null;
   try {
    socket = new Socket(rec.getIP(), this.port);
    DataInputStream dis = new DataInputStream(socket.getInputStream());
    ZipInputStream zis = new ZipInputStream(dis);
    Image image = null;
    try {
     zis.getNextEntry();// 读取下一个 ZIP 文件条目并将流定位到该条目数据的开始处
     image = ImageIO.read(zis);// 把ZIP流转换为图片
     rec.jlabel.setIcon(new ImageIcon(image));
     rec.scroll.setViewportView(rec.jlabel);
     rec.validate();
    } catch (IOException ioe) {}
    try{
//     dis.close();
     zis.close();
    }catch (Exception e) {}
    try {
     TimeUnit.MILLISECONDS.sleep(50);// 接收图片间隔时间
    } catch (InterruptedException ie) {
     ie.printStackTrace();
    }
   } catch (IOException ioe) {
   } finally {
    try {
     socket.close();
    } catch (IOException e) {}
   }
  }
 }
}

/**
 * @author LanXJ @doctime 2010-7-8
 * 访问指定主机的指定端口,向主机发送实例化线程类时传入的操控命令,实现对该主机的操控
 * 默认访问服务端口为DEFAULT_PORT=30012 端口,主机IP为实例化线程类时传入的IP
 * 可以通过changePort和changeIP来修改访问的端口和主机
 * 也可以通过setOperateStr来设置需要发送的操控命令
 * 需要注意的是,修改访问端口或主机必须在线程启动之前修改,否则修改无效
 */
class SendOperate extends Thread {
 public static int DEFAULT_PORT=30012;
 private String ip;
 private int port;// 30012
 private String operateStr;

 public SendOperate(String ip, String operateStr) {
  this.ip = ip;
  this.port = SendOperate.DEFAULT_PORT;
  this.operateStr = operateStr;
 }
 public void setOperateStr(String operateStr){
  this.operateStr=operateStr;
 }
 public void changePort(int port){
  this.port=port;
 }
 public boolean changeIP(String ip){
  if(UtilServer.checkIp(ip)){
   this.ip=ip;
   return true;
  }
  return false;
 }
 public int getPort(){
  return this.port;
 }
 public String getIP(){
  return this.ip;
 }
 public void run() {
  if(this.operateStr==null||this.operateStr.equals("")){
   return;
  }
//  if(this.operateStr.trim().startsWith("mouseMoved")){
//   return;
//  }
  try {
   Socket socket = new Socket(this.ip, this.port);
   OutputStream os = socket.getOutputStream();
   os.write((this.operateStr).getBytes());
   os.flush();
   socket.close();
   System.out.println("INFO: 【SendOperate】ip=" + this.ip + ",port=" + this.port + ",operateStr=/"" + this.operateStr + "/".");
  } catch (UnknownHostException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 
}

/**
 * @author LanXJ @doctime 2010-7-8
 * 服务工具类
 */
class UtilServer{
 public static boolean checkIp(String ip){
  if(ip==null)return false;
  String []dps=ip.split("//.");
  if(dps.length!=4&&dps.length!=6)return false;
  boolean isIp=true;
  for (int i = 0; i < dps.length; i++) {
   try {
    int dp=Integer.parseInt(dps[i]);
    if(dp>255||dp< 0){
     throw new RuntimeException("error IP");
    }
   } catch (Exception e) {
    isIp=false;
    break;
   }
  }
  return isIp;
 }
}
/**
 * @author LanXJ @doctime 2010-7-8
 * serverManage的辅助窗体,内部事件封装了sendOperate的实现
 */
class ServerGUI extends JFrame {
 private static final long serialVersionUID = 2273190419221320707L;
 JLabel jlabel;
 JScrollPane scroll;
 private String ip;
 private int port;
 private boolean boo;
 public boolean getBoo(){
  return this.boo;
 }
 public int getPort(){
  return this.port;
 }
 public void changePort(int port){
  this.port=port;
 }
 public String getIP(){
  return this.ip;
 }
 public boolean changeIP(String ip){
  if(UtilServer.checkIp(ip)){
   this.setTitle(this.getTitle().replace(this.ip, ip));
   this.ip=ip;
   return true;
  }
  return false;
 }

 protected ServerGUI(String IP, String sub) {
  this.boo = true;
  this.ip = IP;
  this.port=SendOperate.DEFAULT_PORT;
  this.setTitle("远程监控--IP:" + IP + "--主题:" + sub);
  this.jlabel = new JLabel();
  this.scroll = new JScrollPane();
  this.scroll.add(this.jlabel);
  scroll.addMouseListener(new MouseAdapter() {
   /*public void mouseClicked(MouseEvent e) {// getMousePosition()
    super.mouseClicked(e);
    //由于加上单击事件后,鼠标按下并快速抬起 就设计到按下、抬起、单击 三个事件,将单击变为了双击
    //所以不实现单击监听
    int x = (int) e.getX() + (int) ServerGUI.this.scroll.getHorizontalScrollBar().getValue();
    int y = (int) e.getY() + (int) ServerGUI.this.scroll.getVerticalScrollBar().getValue();
//    int type = e.getModifiers();//e.BUTTON1_MASK 或 e.BUTTON2_MASK 或 e.BUTTON3_MASK
    String operateStr ="mouseClicked,"+ x + "," + y + "," + e.getModifiers();
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, (operateStr));
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }*/
   
   public void mousePressed(MouseEvent e) {
    super.mousePressed(e);
    int x = (int) e.getX() + (int) ServerGUI.this.scroll.getHorizontalScrollBar().getValue();
    int y = (int) e.getY() + (int) ServerGUI.this.scroll.getVerticalScrollBar().getValue();
//    int type = e.getModifiers();//e.BUTTON1_MASK 或 e.BUTTON2_MASK 或 e.BUTTON3_MASK
    String operateStr ="mousePressed,"+ x + "," + y + "," + e.getModifiers();
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, (operateStr));
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }
   @SuppressWarnings("static-access")
   public void mouseReleased(MouseEvent e) {
    super.mouseReleased(e);
    int x = (int) e.getX() + (int) ServerGUI.this.scroll.getHorizontalScrollBar().getValue();
    int y = (int) e.getY() + (int) ServerGUI.this.scroll.getVerticalScrollBar().getValue();
//    int type = e.getModifiers();//e.BUTTON1_MASK 或 e.BUTTON2_MASK 或 e.BUTTON3_MASK
    String operateStr ="mouseReleased,"+ x + "," + y + "," + e.getModifiers();
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, (operateStr));
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }
  });
  scroll.addMouseMotionListener(new MouseMotionAdapter(){
   public void mouseDragged(MouseEvent e) {
    super.mouseDragged(e);
    int x = (int) e.getX() + (int) ServerGUI.this.scroll.getHorizontalScrollBar().getValue();
    int y = (int) e.getY() + (int) ServerGUI.this.scroll.getVerticalScrollBar().getValue();
    String operateStr ="mouseDragged,"+ x + "," + y + "," + e.getModifiers();
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, operateStr);
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }
   public void mouseMoved(MouseEvent e) {
    super.mouseMoved(e);
    int x = (int) e.getX() + (int) ServerGUI.this.scroll.getHorizontalScrollBar().getValue();
    int y = (int) e.getY() + (int) ServerGUI.this.scroll.getVerticalScrollBar().getValue();
    String operateStr ="mouseMoved,"+ x + "," + y;
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, (operateStr));
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }
  });
  this.addKeyListener(new KeyAdapter(){
   public void keyPressed(KeyEvent e) {
    super.keyPressed(e);
    String operateStr ="keyPress,"+ e.getKeyCode();
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, (operateStr));
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }
   public void keyReleased(KeyEvent e) {
    super.keyReleased(e);
    String operateStr ="keyReleas,"+ e.getKeyCode();
    
    SendOperate sender=new SendOperate(ServerGUI.this.ip, (operateStr));
    sender.changeIP(ServerGUI.this.ip);//同步ip
    sender.changePort(ServerGUI.this.port);//同步port
    sender.start();
   }
   public void keyTyped(KeyEvent e) {
//    super.keyTyped(e);
   }
  });
  this.add(scroll);

  this.setAlwaysOnTop(false);
  Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  this.setBounds(100, 75, (int) screenSize.getWidth() - 200, (int) screenSize.getHeight() - 150);
  // this.setResizable(false);
  this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);// 关闭窗体不做任何事
  this.addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
    boo = false;
    ServerGUI.this.dispose();
    System.out.println("窗体关闭");
    System.gc();
   }
  });
  this.setVisible(true);
  this.validate();

 }
}

 

 

该案例主要分为两个类文件,Server及其中的内部类,Client及其中的内部类。

大家可以参考。

如对Java远控比较感兴趣可以到我的网站上看一下

我们最近用Java开发的一款“黑天鹅远控”软件,并且为开源软件。

该案例为该软件中的一个功能点的源代码,并且已经整理成为单独的完善的案例。

我们的官方网站网址: http://www.blackswansoft.com/

你可以在该网站上下载 “黑天鹅远控”软件。网站上发布了更多的java热点技术,欢迎大家参考。

QQ:1037729010

Email: blackswansoft@163.com


package cn.com.origin.net; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public Server() { } public void listen() throws IOException { ServerSocket server = new ServerSocket(8002); while (true) { try { Socket client = server.accept(); if (client != null) { ServerProcessor processor = new ServerProcessor(client); processor.start(); } } catch (Throwable e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { Server s = new Server(); s.listen(); } } package cn.com.origin.net; import java.awt.AWTException; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import com.sun.image.codec.jpeg.ImageFormatException; import com.sun.image.codec.jpeg.JPEGCodec; public class ServerProcessor extends Thread { // private Socket client; public static final int SEND_IMAGE_SYMBOL = 0x00000000; // private InputStream is; private DataOutputStream dos; private Robot robot; private Rectangle rect; private BufferedImage bm; public ServerProcessor(Socket client) throws IOException, AWTException { // this.client = client; // is = client.getInputStream(); dos = new DataOutputStream(client.getOutputStream()); // bm = ImageIO.read(new File("E:\\Caokai\\001.png")); robot = new Robot(); rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); } public void run() { while (true) { try { bm = robot.createScreenCapture(rect); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ZipOutputStream zis = new ZipOutputStream(bos); zis.setLevel(9); zis.putNextEntry(new ZipEntry("ScreenCapture.jpg")); JPEGCodec.createJPEGEncoder(zis).encode(bm); // ImageIO.write(bm, "jpg", zis); zis.closeEntry(); bos.flush(); byte[] data = bos.toByteArray(); dos.write(SEND_IMAGE_SYMBOL); // System.out.println("Server - data.length = " + data.length); dos.writeInt(data.length); dos.write(data); dos.flush(); // 每秒2帧 Thread.sleep(500); } catch (ImageFormatException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); break; } catch (InterruptedException e) { e.printStackTrace(); } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值