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详见:,注意有无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);
}
}
完美运行。