疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java实现屏幕共享的小程序


 

   

  做一个用于实验室的屏幕监控系统,说到屏幕监控系统,有教师断和学生端,教师端就是Server端,学生端就做Client端。系统里比较有趣的一个地方应该算是屏幕广播与屏幕监控吧,其余什么点名签到,锁屏,定时关机的,就相对来说简单点。

  屏幕广播,在功能实现上面,说白了,就是教师端的机器不断截取屏幕信息,以图片的形式发送到每一个学生端的电脑上面,由此学生能够看见老师在电脑上的操作,这就是所谓的屏幕广播。

  这里面有个麻烦的地方,就是截取屏幕图片的时候,是没有鼠标信息。不过有两种解决办法:

  ①在发送截图信息时,在图片上绘制一个鼠标,这样在学生端就会有两个鼠标,学生端可以移动自己电脑上的鼠标。

  ②发送教师端的鼠标坐标到学生端上,学生端的电脑鼠标根据坐标信息实时移动,这里其实是涉及到控制的功能了,学生端就不能移动鼠标了。

  屏幕监控相对棘手点,其实这是这包含俩功能:①教师监控所有学生电脑屏幕的功能;②教师控制某一个学生的电脑; 因为涉及到并发,每个client都要实时的把屏幕信息发到教师端上,会有点麻烦,不过还是可以实现。

  下面是不带鼠标的屏幕共享功能,比较简单,有待完善,不过可以作为一个工具类在后面集成使用。后面补充了把鼠标画上去的代码,只需要3行。

  首先是教师端Server:

  package Test;

  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.net.ServerSocket;

  import java.net.Socket;

  import java.util.zip.ZipEntry;

  import java.util.zip.ZipOutputStream;

  import javax.imageio.ImageIO;

  /*

  * ly 2014-11-20

  * 该类实时发送截屏消失,多线程实现,不包含鼠标信息,且没有做对每个Client做优化处理

  */

  public class SendScreenImg extends Thread

  {

  public static int SERVERPORT=8000;

  private ServerSocket serverSocket;

  private Robot robot;

  public Dimension screen;

  public Rectangle rect ;

  private Socket socket;

  public static void main(String args[])

  {

  new SendScreenImg(SERVERPORT).start();

  }

  //构造方法 开启套接字连接 机器人robot 获取屏幕大小

  public SendScreenImg(int SERVERPORT)

  {

  try {

  serverSocket = new ServerSocket(SERVERPORT);

  serverSocket.setSoTimeout(864000000);

  robot = new Robot();

  } catch (Exception e) {

  e.printStackTrace();

  }

  screen = Toolkit.getDefaultToolkit().getScreenSize(); //获取主屏幕的大小

  rect = new Rectangle(screen); //构造屏幕大小的矩形

  }

  @Override

  public void run()

  {

  //实时等待接收截屏消息

  while(true)

  {

  try{

  socket = serverSocket.accept();

  System.out.println("学生端口已经连接");

  ZipOutputStream zip = new ZipOutputStream(new DataOutputStream(socket.getOutputStream()));

  zip.setLevel(9); //设置压缩级别

  BufferedImage img = robot.createScreenCapture(rect);

  zip.putNextEntry(new ZipEntry("test.jpg"));

  ImageIO.write(img, "jpg", zip);

  if(zip!=null)zip.close();

  System.out.println("Client正在实时连接");

  } catch (IOException ioe) {

  System.out.println("连接断开");

  } finally {

  if (socket != null) {

  try {

  socket.close();

  } catch (IOException e) {e.printStackTrace();}

  }

  }

  }

  }

  }

  然后是学生端Client:

  package Test;

  import java.awt.Frame;

  import java.awt.Image;

  import java.awt.event.WindowAdapter;

  import java.awt.event.WindowEvent;

  import java.io.DataInputStream;

  import java.io.IOException;

  import java.net.Socket;

  import java.util.concurrent.TimeUnit;

  import java.util.zip.ZipInputStream;

  import javax.imageio.ImageIO;

  import javax.swing.ImageIcon;

  import javax.swing.JFrame;

  import javax.swing.JLabel;

  /*

  * ly 2014-11-20

  * 该类用于接收教师端的屏幕信息,不包括鼠标,待优化

  */

  public class ReceiveImages extends Thread{

  public BorderInit frame ;

  public Socket socket;

  public String IP;

  public static void main(String[] args){

  new ReceiveImages(new BorderInit(), "127.0.0.1").start();

  }

  public ReceiveImages(BorderInit frame,String IP)

  {

  this.frame = frame;

  this.IP=IP;

  }

  public void run() {

  while(frame.getFlag()){

  try {

  socket = new Socket(IP,8000);

  DataInputStream ImgInput = new DataInputStream(socket.getInputStream());

  ZipInputStream imgZip = new ZipInputStream(ImgInput);

  imgZip.getNextEntry(); //到Zip文件流的开始处

  Image img = ImageIO.read(imgZip); //按照字节读取Zip图片流里面的图片

  frame.jlbImg.setIcon(new ImageIcon(img));

  System.out.println("连接第"+(System.currentTimeMillis()/1000)%24%60+"秒");

  frame.validate();

  TimeUnit.MILLISECONDS.sleep(50);// 接收图片间隔时间

  imgZip.close();

  } catch (IOException | InterruptedException e) {

  System.out.println("连接断开");

  }finally{

  try {

  socket.close();

  } catch (IOException e) {}

  }

  }

  }

  }

  //Client端窗口辅助类,专门用来显示从教师端收到的屏幕信息

  class BorderInit extends JFrame

  {

  private static final long serialVersionUID = 1L;

  public JLabel jlbImg;

  private boolean flag;

  public boolean getFlag(){

  return this.flag;

  }

  public BorderInit()

  {

  this.flag=true;

  this.jlbImg = new JLabel();

  this.setTitle("远程监控--IP:" + "--主题:" );

  this.setSize(400, 400);

  //this.setUndecorated(true); //全屏显示,测试时最好注释掉

  //this.setAlwaysOnTop(true); //显示窗口始终在最前面

  this.add(jlbImg);

  this.setLocationRelativeTo(null);

  this.setExtendedState(Frame.MAXIMIZED_BOTH);

  this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

  this.setVisible(true);

  this.validate();

  //窗口关闭事件

  this.addWindowListener(new WindowAdapter() {

  public void windowClosing(WindowEvent e) {

  flag=false;

  BorderInit.this.dispose();

  System.out.println("窗体关闭");

  System.gc(); //垃圾回收

  }

  });

  }

  }

  很晚了,从未成品中抽取了这么个小功能,因为答应某位童鞋给链接的,距离成品还有很多要写,后续补上吧。

  后续补充:

  把鼠标画到屏幕截图的方法,在SendScreenImg类中 BufferedImage img = robot.createScreenCapture(rect);后面,添加下面三行代码:

  BufferedImage cursor= ImageIO.read(new File("img/cursor.png")); //把鼠标加载到缓存中

  Point p= MouseInfo.getPointerInfo().getLocation(); //获取鼠标坐标

  img.createGraphics().drawImage(cursor, p.x, p.y, null); //在图片画上鼠标

  嗯,记得在工程下面建立一个img文件夹,在文件夹中放置名为cursor.png的鼠标图片,一定要png格式的,要求底色透明,可以去下载,也可以自己p图。