最近在做软件软件工程的课程设计,做一个用于实验室的屏幕监控系统,参考各种前人代码,最后领悟之后要转换自己的代码,初学者都是这样模仿过来的。

      说到屏幕监控系统,有教师断和学生端,教师端就是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图。

           给张运行时候的截图(按理说应该是有3个鼠标的,但是QQ截图也是没有的鼠标):

            本文出自博客园兰幽http://www.cnblogs.com/LZYY/

java实现屏幕共享的小程序的更多相关文章

  1. Java之——实现微信小程序加密数据解密算法

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/79450115 一.概述 微信推出了小程序,很多公司的客户端应用不仅具有了APP.H ...

  2. java服务端微信小程序支付

    发布时间:2018-10-05   技术:springboot+maven   概述 java微信小程序demo支付只需配置支付一下参数即可运行 详细 代码下载:http://www.demodash ...

  3. 「小程序JAVA实战」微信小程序工程结构了解(五)

    转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-05/ 微信小程序工程结构 audio,button,canvas,checkbox 都是由4个文件 ...

  4. 「小程序JAVA实战」微信小程序简介(一)

    转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-01/ 一直想学习小程序,苦于比较忙,加班比较多没时间,其实这都是理由,很多时候习惯了搬砖,习惯了固 ...

  5. JAVA编写的断点续传小程序

    上了一周的课,今天终于可以休息了,太棒了,今天闲着无聊使用java语言写了一个断点续传的小程序来分享给大家, 首先要下载个用于网络请求的框架:我这里给出地址,是用的Apache的HttpClient: ...

  6. java后台获取微信小程序openid

    一.jar包准备 1.在网盘下载 链接:https://pan.baidu.com/s/15HAAWOg_yn768g4s9IrcPg 提取码:hgj0 二.在pom文件中添加依赖 1.将外部的引入的 ...

  7. java全栈商业小程序开发

    此次开发只为学习和巩固,第一次学习开发 一.开发前需要了解: 开发框架MVVM.痛点.开源工具.VUE前端框架.微信支付模块.uni-app前端框架.小程序申请.开发工具下载.编写测试小程序.小程序结 ...

  8. 「小程序JAVA实战」微信小程序的简要注册流程(二)

    转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-02/ 了解了小程序的历史和它未来的前景,我们开始注册小程序 注册小程序 可以参考官网介绍:http ...

  9. Java Servlet:服务器小程序

    servlet:服务器小程序 servlet是一个接口,接口是一种规范,因此servlet是一种规范 一个类声明为抽象类的原因: 不包含抽象方法,不想被实例化 包含抽象方法,子类有对抽象方法的不同实现 ...

随机推荐

  1. 获取DOM

    <template> <div> <header-vue :msg="msg" ref="header">heheh< ...

  2. js的单例

     对于 JS 来说,巨大的灵活性使得其可以有多种方式实现单例模式,使用闭包方式来模拟私有数据,按照其思路可得: var single = (function(){ var unique; functi ...

  3. 用Jquery控制元素的上下移动 实现排序功能

    在页面上,控制元素上下移动,进行排序是我们比较常用的功能,今天我用jQuery 写个 简单方便,功能齐全的实现方式. 话不多说,直接上代码,下面是基础的引入jq和html元素部分: <scrip ...

  4. 『Python基础-14』匿名函数 `lambda`

    匿名函数和关键字lambda 匿名函数就是没有名称的函数,也就是不再使用def语句定义的函数 在Python中,如果要声匿名函数,则需要使用lambda关键字 使用lambda声明的匿名函数能接收任何 ...

  5. 小程序开发-10-新版Music组件、组件通信与wxss样式复用

    加入缓存提升用户体验 思路:先从缓存中寻找数据或者从服务器中获取数据写入缓存中 优点:减少网络访问次数,提升用户体验 解决缓存带来的问题 问题:比如原先是不喜欢的在点击喜欢的时候,跳到下一期刊后返回来 ...

  6. js闭包的理解-目前网上分析的最透彻文章

    js的闭包对于大家实际上并不陌生,但是真正敢说自己完全理解的人并不多.笔者在网上看到分析闭包的文章非常多,篇幅用的非常多,但是实际上分析的并不到位,或者根本就是不正确的.我有时候都在想,写这些文章的人 ...

  7. SAP Odata実行命令(1)

    $count $Orderby:desc/asc ※$Orderby=ソートする項目 desc降順/asc昇順 を指定すること $Filter: $Skip,Top and Inline count: ...

  8. google friendly testing

    https://www.google.com/webmasters/tools/mobile-friendly/?mc_cid=cc21b18877&mc_eid=cf2bbeb9b2 htt ...

  9. Nginx初体验(一):nginx介绍

    今天我们来介绍一下Nginx. Nginx是一款轻量级的Web服务器/反向代理服务器以及电子邮件(IMAP/POP3)代理服务器 特点: 反向代理,负载均衡,动静分离 首先我们来介绍一下正向代理服务器 ...

  10. Redis的n种妙用,不仅仅是缓存

    redis是键值对的数据库,常用的五种数据类型为字符串类型(string),散列类型(hash),列表类型(list),集合类型(set),有序集合类型(zset) Redis用作缓存,主要两个用途: ...