java動態執行程式碼或者第三方程式並返回pid,殺掉程序
阿新 • • 發佈:2018-11-05
java動態執行程式碼或者第三方程式並返回pid,殺掉程序
使用java動態執行Java程式碼或者呼叫第三方軟體,如下程式碼即可
Process child = Runtime.getRuntime().exec(cmd);
只要寫好cmd命令即可,如何同時返回程序的pid呢,這樣可以準確的殺掉程序,這裡我們需要一個jar用於呼叫dll
網上,maven倉庫可下載,或者下載結尾原始碼
首先把jar buildpath引入,建立一個介面
import com.sun.jna.Library; import com.sun.jna.Native; import constant.OtherConstant; public interface Kernel32 extends Library { public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class); public long GetProcessId(Long hProcess); }
呼叫方法
// 獲取pid public static long getProcessPID(Process child) { long pid = -1; Field field = null; try { field = child.getClass().getDeclaredField("handle"); field.setAccessible(true); pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(child)); } catch (Exception e) { e.printStackTrace(); } return pid; }
接下來實戰模擬一下,首先使用runtime執行class檔案,書寫程式碼,編譯成class,然後使用runtime執行它,示例程式碼:
package example; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class JavaProcess1 { public static void main(String[] args) { for (int i = 0; i < 100; i++) { System.out.println(i); // appendFile("C:\\RICO\\JavaProcess1.txt", "test: " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } // 追加檔案 public static boolean appendFile(String filePath, String content) { FileWriter fw = null; try { // 如果檔案存在,則追加內容 // 如果檔案不存在,則建立檔案 File f = new File(filePath); fw = new FileWriter(f, true); PrintWriter pw = new PrintWriter(fw); pw.println(content); pw.flush(); fw.flush(); pw.close(); fw.close(); return true; } catch (IOException e) { e.printStackTrace(); return false; } } }
如何編譯java執行class詳見:https://blog.csdn.net/rico_zhou/article/details/79873344,注意有無package名的區別
接下來建立兩個工具類,一個是用於執行cmd,一個是執行緒擷取輸出流
執行類
package utils;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import constant.OtherConstant;
import constant.SpiderConstant;
public class RunUtils {
public static Map<String, Object> messageMap = new HashMap<String, Object>();
// 執行程式碼有兩種方式,一種是通過反射動態執行,一種是另起程序,這裡選擇另起程序
public static void run(String cmd, int flag) {
long pid;
try {
Process child = Runtime.getRuntime().exec(cmd);
messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_PROCESS, child);
// 獲取此子程序的pid,只windows系統
pid = getProcessPID(child);
messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_PID, pid);
// 獲取程式輸入流
// OutputStream os = child.getOutputStream();
// 正常輸出流和異常輸出流
InputStream stdin = child.getInputStream();
InputStream stderr = child.getErrorStream();
// 啟動執行緒,獲取輸出流
if (flag == 0) {
ConsoleSimulator cs1 = new ConsoleSimulator(stdin, 0);
ConsoleSimulator cs2 = new ConsoleSimulator(stderr, 1);
Thread tIn = new Thread(cs1);
Thread tErr = new Thread(cs2);
tIn.start();
tErr.start();
}
// // 啟動執行緒獲取輸出之後不在阻塞,直接返回,列印輸出以輪播形式推送前臺
// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_INPUTSTREAMTHREAD,
// tIn);
// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_INPUTSTREAMCONSOLE,
// cs1);
// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_ERRORSTREAMTHREAD,
// tErr);
// messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_ERRORSTREAMCONSOLE,
// cs2);
// 正在執行
messageMap.put(SpiderConstant.SPIDER_KEYWORD_PROCESSMAP_RUNSTATUS, 0);
// int result = child.waitFor();
// tIn.join();
// tErr.join();
} catch (Exception e) {
e.printStackTrace();
}
}
// 阻塞
public static String[] run2(String cmd) {
String returnPrintContent = null;
String returnErrorContent = null;
String[] returnContent = new String[2];
try {
Process child = Runtime.getRuntime().exec(cmd);
// 獲取程式輸入流
OutputStream os = child.getOutputStream();
// 正常輸出流和異常輸出流
InputStream stdin = child.getInputStream();
InputStream stderr = child.getErrorStream();
// 啟動執行緒
ConsoleSimulator cs1 = new ConsoleSimulator(stdin, 0);
ConsoleSimulator cs2 = new ConsoleSimulator(stderr, 1);
Thread tIn = new Thread(cs1);
Thread tErr = new Thread(cs2);
tIn.start();
tErr.start();
int result = child.waitFor();
tIn.join();
tErr.join();
returnPrintContent = cs1.getReturnPrintContent();
returnErrorContent = cs2.getReturnErrorContent();
// 處理中文亂碼,需更改伺服器端編碼
// 0是全部資訊
returnContent[0] = returnPrintContent;
// 1是錯誤資訊
returnContent[1] = returnErrorContent;
return returnContent;
} catch (Exception e) {
e.printStackTrace();
return returnContent;
}
}
// 獲取pid
public static long getProcessPID(Process child) {
long pid = -1;
Field field = null;
try {
field = child.getClass().getDeclaredField("handle");
field.setAccessible(true);
pid = Kernel32.INSTANCE.GetProcessId((Long) field.get(child));
} catch (Exception e) {
e.printStackTrace();
}
return pid;
}
}
程式碼中常量資訊請下載原始碼檢視
輸出流執行緒
package utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import constant.CodingConstant;
import constant.CommonSymbolicConstant;
//另起執行緒擷取程式流
public class ConsoleSimulator implements Runnable {
public boolean isStop = false;
public int INFO = 0;
public int ERROR = 1;
public InputStream is;
public int type;
public StringBuilder returnPrintContent = new StringBuilder();
public StringBuilder returnErrorContent = new StringBuilder();
public StringBuilder returnCommonContent = new StringBuilder();
public ConsoleSimulator(InputStream is, int type) {
this.is = is;
this.type = type;
}
public void run() {
InputStreamReader isr = null;
try {
isr = new InputStreamReader(is, CodingConstant.CODING_UTF_8);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
BufferedReader reader = new BufferedReader(isr);
String s;
try {
// 此地方執行python的時候阻塞,不知為何執行緒會停止
while ((!isStop) && (s = reader.readLine()) != null) {
if (s.length() != 0) {
if (type == INFO) {
System.out.println(s);
returnPrintContent.append(s + CommonSymbolicConstant.LINEBREAK2);
} else {
returnErrorContent.append(s + CommonSymbolicConstant.LINEBREAK2);
}
}
}
isStop = true;
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
isr.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getReturnPrintContent() {
return returnPrintContent.toString();
}
public String getReturnErrorContent() {
return returnErrorContent.toString();
}
public String getReturnCommonContent() {
return returnCommonContent.toString();
}
public void stop() {
isStop = true;
}
}
準備工作完成,開始測試,首先測試無阻塞不獲取輸出流,注意示例程式碼執行時長為100秒,我們在執行10秒後殺掉
package runkillprocess;
import constant.CMDConstant;
import constant.SpiderConstant;
import utils.RunUtils;
//使用runtime呼叫第三方程式
public class RunProcess {
public static void main(String[] args) {
// 執行無阻塞呼叫
// 子程序動態執行java,class檔案
long pid = runJavaProcess(1);
System.out.println(pid);
// 十秒後殺掉程序
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stopProcess(pid);
// 執行阻塞呼叫
}
public static long runJavaProcess(int flag) {
String cmd = "java -cp C:\\RICO example.JavaProcess1";
RunUtils.run(cmd, flag);
// 獲取pid
return (long) RunUtils.messageMap.get("pid");
}
public static void stopProcess(long pid) {
// 拼接命令
String cmd = "taskkill /PID " + pid + " /F";
// 執行命令
String[] returnContent = RunUtils.run2(cmd);
}
}
若不殺掉程序且不獲取輸出流,則情況如下:
我們可以看到主程式執行一下就結束了,獲取了動態執行的java進行pid為11304,開啟工作管理員你會發現11304的程序依然在進行,表明我執行成功。當我們選擇10秒後殺掉程序這種情況執行程式碼,注意管理器中的java程序會在十秒後結束,殺掉成功。
如果選擇讀取輸出流則控制檯將會獲取跟cmd執行class一樣的內容。
下面我們選擇一個第三方軟體試試。呼叫notepad++開啟一個檔案,10秒後殺掉
package runkillprocess;
import constant.CMDConstant;
import constant.SpiderConstant;
import utils.RunUtils;
//使用runtime呼叫第三方程式
public class RunProcess {
public static void main(String[] args) {
// 執行無阻塞呼叫
// 子程序呼叫notepad++,開啟一個檔案
long pid = runJavaProcess(1);
System.out.println(pid);
// 十秒後殺掉程序
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stopProcess(pid);
// 執行阻塞呼叫
}
public static long runJavaProcess(int flag) {
String cmd = "\"C:\\Program Files (x86)\\Notepad++\\notepad++.exe\" C:\\RICO\\icon2.txt";
RunUtils.run(cmd, flag);
// 獲取pid
return (long) RunUtils.messageMap.get("pid");
}
public static void stopProcess(long pid) {
// 拼接命令
String cmd = "taskkill /PID " + pid + " /F";
// 執行命令
String[] returnContent = RunUtils.run2(cmd);
}
}
完美執行。