Java实现远程屏幕监视

开发 后端
本篇文章主要介绍在Java中要实现远程屏幕监视,远程屏幕监视使得控制方可以在远程主机上监视其它一台机器,其主要实现原理就是将被控制机器的屏幕作为图片传送给监视方。

远程屏幕监视使得控制方可以在远程主机上监视其它一台机器,其主要实现原理就是将被控制机器的屏幕作为图片传送给监视方,在Java中要实现远程屏幕监视,主要解决以下几个问题即可:

1:将当前屏幕的显示内容捕捉为图片

2:将捕捉的图片发送到远程控制主机

3:远程控制主机接收到在本地显示

4:利用多线程重复上面三步达到实时更新

说起来怎么这么简单啊,今天试着做了一下远程屏幕监视的实验,发现还真不是这么简单的,把我的心得总结出来共享一下,希望对你有用。

将当前屏幕显示内容捕捉为图片

Java代码

 

  1. Robot robot = new Robot();     
  2. //要捕捉的屏幕显示范围,下面以全屏示例说明     
  3. Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());     
  4. BufferedImage bm = robot.createScreenCapture(rect);    

 

通过上面几行代码就把屏幕的当前显示内容保存为内存中的BufferedImage对象,这个确实简单.

将捕捉的图片发送到远程控制主机

要达到实时监控,怎么保证发送效率,在网络状况不良好时怎么保证发送时使用带宽

因为要不停地往控制机上发送图片,所以传送的图片不能太大,否则会影响实时性,当网络状况不好时,占用带宽过多则更加会给实时性带来严峻的考验,解决的方法有两个:

1:使用jpg格式的图片进行传输。

jpg是一种支持高度压缩技术的图片格式,它所存储的信息不包含透明度,同等质量的情形下相对来说比png,gif等格式的图片要小很多,当然,文件大小是以图像质量为代价的,如果你一味地追求压缩后的大小,图像质量就会受损了。我在实验中使用大小为28394字节的png图片经过jpg压缩后大小仅剩5815字节(不是PS,整个过程全部使用Java完成)。

2:将用图片生成的字节数据先压缩再传送。

这一步是仁者见仁,智者见智了,有人说没有必要,jgp格式的图片再压缩也小不了多少。确实是这样的,我在实验中把5815字节大小的jpg经过zip压缩后为大小变为5702,有点小作用,实际应用中压缩与否就看你了(压缩其它格式的图片效果可能会明显一点,我在实验中把一个大小为883078字节的bmp图片压缩后大小仅为16849字节,很可观,达到了52:1)。

我能想到的就是这两点了,欢迎各位仁智双全的人补充。下面就是这两点用到的Java技术,Java高手就直接跳过吧。

使用Java将图片处理成jpg格式

Java代码

 

  1. //outputstream就是要写入处理后的jpg图片的输出流,要保存到文件的话就用FileOutputStream     
  2. JPEGCodec.createJPEGEncoder(outputstream).encode(bm);     
  3. ImageIO.write(bm, "jpg", outputstream);    

 

这两种方法有什么差别呢?别的我不知道,就平均效率来说,第二种是第一种的2倍,我实验中转换了10次,使用的时间分别是125和250(单位是百分之一毫秒,机子有点慢的说).

把图片数据转换为字节数组

Java代码

 

  1. ByteArrayOutputStream bos = new ByteArrayOutputStream();     
  2. JPEGCodec.createJPEGEncoder(bos).encode(bm);     
  3. // 上句也可以用 ImageIO.write(bm, "jpg", bos)实现     
  4. bos.flush();     
  5. byte[] data = bos.toByteArray();    

 

将生成的字节数组进行zip压缩

Java代码

 

  1. ZipOutputStream zos = new ZipOutputStream(bos);     
  2. zos.setLevel(Deflater.BEST_COMPRESSION);     
  3. //下面我以ScreenCapture.jpg说明     
  4. zos.putNextEntry(new ZipEntry("ScreenCapture.jpg"));     
  5. zos.write(data);     
  6. zos.closeEntry();    

 

好了,这个时候就可以把字节数组发往监控机器了,如果你发了,你就知道,问题又来了(不会吧!)。

1:既然是采用多线程发送多张图片,那么对于一张图片,接收方怎么知道你发完了呢?

2:如果要发其它的数据,比如鼠标点击等,接收方又怎么区分什么时候发的是图片,什么时候发的是其它的……

对于这两点问题,最直接的解决方法是当数据发送完成后关闭发送字节的输出流,第二次发送时重新建立连接(网上确实有人这样肆无忌惮地做),这种方法采用不采用就看良心了(汗)。我采用的解决方法是,每次发送数据前都告诉接收方要发什么东西(解决问题2),同时告诉它我发了多少字节(解决问题1),接收方只要接收了这么多字节数,就表示本次发送完成,最后再发送真正要发送的内容(图片等),说简单点就是,发送的消息结构如下:

【标识位 大小 消息】

标识位:采用一个整型,其实是一个byte,占一个字节

大小:一个整型,占四个字节

消息:实际要发送的字节数组,长度就是字节数组的长度

这样接收方每次都是先读取一个整数,判断发送方是要发送什么消息,然后再判断消息的大小,然后再接收指定大小的消息,最后完成本次发送转入下一次接收工作。

采用Socket的方式进行消息的发送

Java代码

 

  1. DataOutputStream dos = new DataOutputStream(client.getOutputStream());     
  2. //SEND_IMAGE_SYMBOL是一个标识位,你随便定义,只要保证能与其它标识位区分就行     
  3. dos.write(SEND_IMAGE_SYMBOL);     
  4.     
  5. dos.writeInt(data.length);     
  6. dos.write(data);     
  7. dos.flush();    

 

啊,真不容易,终于发送出去了!不知道那边接收到了没有?那现在就去追踪报道吧。

远程控制主机接收消息

Java代码

 

 

 

  1. //先要判断消息的类型     
  2.  DataInputStream reader = new DataInputStream(socket.getInputStream());     
  3.  int msgSymbol = reader.read();     
  4.  //还记得这个SEND_IMAGE_SYMBOL吗     
  5.  if (msgSymbol == SEND_IMAGE_SYMBOL)     
  6.  {     
  7.      //哦,是要发送图片啊。让我看看你的图片有多大     
  8.      int msgSize = reader.readInt();     
  9.       
  10.     //晕,你网速好也不用发这么大吧,我一次接收不完的,不过幸好我有准备     
  11.     byte[] buffer = new byte[msgSize];     
  12.     int length = 0;     
  13.     
  14.     while (length < msgSize)     
  15.     {     
  16.         int readSize = reader.read(buffer, length, msgSize - length);     
  17.     
  18.         if (readSize > 0)     
  19.         {     
  20.             length = length + readSize;     
  21.         }     
  22.         else    
  23.         {     
  24.             break;     
  25.         }     
  26.     }     
  27.     //这是非常关键的,图片太大时一次性是读不完的,一定要使用缓冲重复读取。     
  28.     
  29.     //人家给我发送的消息是图片,怎么把字节数组还原成图片呢?     
  30.     ByteArrayInputStream bis = new ByteArrayInputStream(buffer);     
  31.     ZipInputStream zis = new ZipInputStream(bis);     
  32.     //读取压缩的数据内容。     
  33.     ZipEntry ze = zis.getNextEntry();     
  34.     BufferedImage bi = ImageIO.read(zis);     
  35.     //或者BufferedImage bi = JPEGCodec.createJPEGDecoder(zis).decodeAsBufferedImage();     
  36.     //上面两行代码的差别已经说过了     
  37.     //另外,如果在发送的时候你没有进行压缩,把上面的zis换成bis就行。     
  38.     
  39.     
  40.     //有了BufferedImage对象,剩下的就是把它显示出来了进行远程"偷窥",任何一个支持图片显示的swing组件你都以用,我在实验中用的是JPanel,一个简单又支持双缓冲的组件。     
  41. }    

最后,就是使用多线程重复上面的步骤进行实时监控了。有什么问题欢迎指正。

本次实验进行的还算成功,成功偷窥了自己的桌面。谢谢你坚持看完我的文章,向你致敬!

下面是本次实验的运行图:

 

【编辑推荐】
责任编辑:金贺 来源: JavaEye博客
相关推荐

2021-01-20 23:43:26

远程监控网络安全

2021-09-03 00:43:54

微信功能技巧

2021-09-04 00:15:11

微信功能技巧

2013-12-26 16:26:04

2019-03-04 09:00:00

屏幕共享远程访问Windows

2011-07-14 16:55:36

Java远程访问Domino数据库

2013-01-14 11:03:30

2013无线充电柔性屏幕

2011-03-28 16:12:55

mysql自动远程备份

2009-06-30 15:19:00

阻塞读取远程文件Java多线程

2011-06-01 16:10:42

JNBridge

2010-12-31 13:30:12

2011-04-06 13:28:46

Delphi

2021-09-13 06:33:27

远程工作ITCIO

2010-10-11 11:58:12

2010-05-25 18:29:30

MySQL远程访问

2009-08-12 13:11:24

C#实现远程线程插入

2014-04-01 11:17:16

2009-08-27 15:50:23

屏幕取词

2011-12-19 13:29:12

Java

2011-04-06 08:54:25

Nagios监视
点赞
收藏

51CTO技术栈公众号