Java实现远程屏幕监视

Robot robot = new Robot();
		//要捕捉的屏幕显示范围,下面以全屏示例说明  
		Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); 
	    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格式
 
//outputstream就是要写入处理后的jpg图片的输出流,要保存到文件的话就用FileOutputStream 
  JPEGCodec.createJPEGEncoder(outputstream).encode(bm);  
ImageIO.write(bm, "jpg", outputstream);
 这两种方法有什么差别呢?别的我不知道,就平均效率来说,第二种是第一种的2倍,我实验中转换了10次,使用的时间分别是125和250(单位是百分之一毫秒,机子有点慢的说).
  把图片数据转换为字节数组
  
ByteArrayOutputStream bos = new ByteArrayOutputStream();  
JPEGCodec.createJPEGEncoder(bos).encode(bm);  
// 上句也可以用 ImageIO.write(bm, "jpg", bos)实现   bos.flush();   byte[] data = bos.toByteArray();
 将生成的字节数组进行zip压缩
  
ZipOutputStream zos = new ZipOutputStream(bos);  
zos.setLevel(Deflater.BEST_COMPRESSION); 
  //下面我以ScreenCapture.jpg说明  
zos.putNextEntry(new ZipEntry("ScreenCapture.jpg"));
   zos.write(data); 
  zos.closeEntry();
 好了,这个时候就可以把字节数组发往监控机器了,如果你发了,你就知道,问题又来了(不会吧!)。
  1:既然是采用多线程发送多张图片,那么对于一张图片,接收方怎么知道你发完了呢?
  2:如果要发其它的数据,比如鼠标点击等,接收方又怎么区分什么时候发的是图片,什么时候发的是其它的……
  对于这两点问题,最直接的解决方法是当数据发送完成后关闭发送字节的输出流,第二次发送时重新建立连接(网上确实有人这样肆无忌惮地做), 这种方法采用不采用就看良心了(汗)。我采用的解决方法是,每次发送数据前都告诉接收方要发什么东西(解决问题2),同时告诉它我发了多少字节(解决问题 1),接收方只要接收了这么多字节数,就表示本次发送完成,最后再发送真正要发送的内容(图片等),说简单点就是,发送的消息结构如下:
  【标识位 大小 消息】
  标识位:采用一个整型,其实是一个byte,占一个字节
  大小:一个整型,占四个字节
  消息:实际要发送的字节数组,长度就是字节数组的长度
  这样接收方每次都是先读取一个整数,判断发送方是要发送什么消息,然后再判断消息的大小,然后再接收指定大小的消息,最后完成本次发送转入下一次接收工作。
  采用Socket的方式进行消息的发送
  
DataOutputStream dos = new DataOutputStream(client.getOutputStream()); 
  //SEND_IMAGE_SYMBOL是一个标识位,你随便定义,只要保证能与其它标识位区分就行 
  dos.write(SEND_IMAGE_SYMBOL);   
  dos.writeInt(data.length); 
  dos.write(data);  
dos.flush();
 啊,真不容易,终于发送出去了!不知道那边接收到了没有?那现在就去追踪报道吧。
  远程控制主机接收消息

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

	
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值