强制终止子进程的Java工具/方法

发布于 2024-10-16 08:35:45 字数 869 浏览 2 评论 0原文

我正在寻找一个 Java 工具/包/库,可以让我强制杀死 一个子进程。

该工具/包/库必须在 Windows 平台上运行(强制)。 需要对 Linux/Unix 的支持。

我的问题

我的 Java 代码创建了一个子进程,该进程根本不会对 终止子进程的标准 Java 方法:process.destroy(),以及, 因为我没有孩子的源代码,所以我无法将其编程为 更好地处理终止请求。

我尝试关闭子进程的错误输入和输出流 在调用 destroy() 之前,并且没有任何效果。

我什至尝试将 ctrlBreak 信号(char=3)直接传递到 child.getOutputStream() 再次收到相同的结果。

我最终找到的解决方法是:

  1. 在创建子进程时获取子进程的 PID 这可以在 Windows 中通过比较进程列表来完成 子进程创建之前和之后 (getRuntime().exec("tasklist /v"))

  2. 使用子进程的 PID 发出强制终止系统命令
    在 Windows 中: getRuntime().exec("taskkill /pid " + childPid + " /f")

但是 - 这是复杂的代码,我不想调试和维护,加上问题 我毫不怀疑,许多其他 java 开发人员以前也遇到过这种情况, 这让我希望这样的 Java 工具/包/库已经存在。

我只是不知道它的名字...

PS:我的子进程是由 Runtime.getRuntime().exec(cmd) 创建的,但是 我使用 ProcessBuilder 得到了相同的行为。

I am looking for a Java tool/package/library that will allow me to force-kill
a child process.

This tool/package/library must work on Windows platform (mandatory).
Support for Linux/Unix is desired.

My Problem

My Java code creates a child process that will simply not react to the
standard Java way for killing a child process: process.destroy(), and,
since I do not have the child's source code, I cannot program it to
better handle termination requests.

I have tried closing the child process' error input and output stream
before calling destroy(), and for no effect.

I have even tried passing ctrlBreak signal (char=3) directly into
child.getOutputStream(), and again have received the same results.

The workaround I have finally managed to find was to:

  1. Obtain the child's PID upon its creation
    This can be done in Windows by diffing the process lists
    before and after the child's creation (getRuntime().exec("tasklist /v"))

  2. Use the child's PID to issue a force kill system command
    in Windows: getRuntime().exec("taskkill /pid " + childPid + " /f")

But - this is complex code I have no desire to debug and maintain, plus the problem
itself, I have no doubt, was previously encountered by many other java developers,
which leads me to the hope that such a Java tool/package/library already exists.

I just don't know its name...

PS: My child process was created by Runtime.getRuntime().exec(cmd), but
I get the same behaviour using a ProcessBuilder.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冬天旳寂寞 2024-10-23 08:35:45

有一种更精简的方法可以使用 Java JNA 来完成此操作。

这绝对适用于 Windows 和 Linux,我认为您也可以对其他平台执行相同的操作。

Java进程处理的最大问题是缺少一种方法来获取使用untime.getRuntime().exec()启动的进程的进程ID。

假设你得到了一个进程的pid,你总是可以在linux中启动kill -9命令,或者在windows中使用类似的方法来终止进程。

这是一种在 Linux 上获取本机进程 id 的方法(从 selenium 框架借用,:)),在 JNA 的帮助下,这也可以在 Windows 上完成(使用本机 Windows API 调用)。

为此(对于 Windows),您首先必须在 JAVA NATIVE ACCESS 获取 JNA 库(JNA):下载或从 maven 获取

看下面的代码,它将获取(在本示例中为 Windows)程序的 pid(大部分代码实际上是让 java 程序运行的碎片):

import com.sun.jna.*;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

static interface Kernel32 extends Library {

    public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);

    public int GetProcessId(Long hProcess);
}

public static void main(String[] args) {
    try {
        Process p;

        if (Platform.isWindows())
            p = Runtime.getRuntime().exec("cmd /C ping msn.de");
        else if (Platform.isLinux())
            p = Runtime.getRuntime().exec("cmd /C ping msn.de");

        System.out.println("The PID: " + getPid(p));

        int x = p.waitFor();
        System.out.println("Exit with exitcode: " + x);

    } catch (Exception ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public static int getPid(Process p) {
    Field f;

    if (Platform.isWindows()) {
        try {
            f = p.getClass().getDeclaredField("handle");
            f.setAccessible(true);
            int pid = Kernel32.INSTANCE.GetProcessId((Long) f.get(p));
            return pid;
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    } else if (Platform.isLinux()) {
        try {
            f = p.getClass().getDeclaredField("pid");
            f.setAccessible(true);
            int pid = (Integer) f.get(p);
            return pid;
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    else{}
    return 0;
}
}

希望这会有所帮助,;)...

There is a leaner way to do this using Java JNA.

This works definitely for Windows and Linux, i assume that you can do the same for other platforms too.

The biggest problem of Java process handling is the lack of a method to get the process id of the process started with untime.getRuntime().exec().

Assuming you got the pid of a process, you always can start a kill -9 command in linux, or use similar ways to kill a process in windows.

Here is a way to get the process id natively for linux (borrowed from the selenium framework, :) ), and with the help of JNA this also can be done for windows (using native Windows API calls).

For this to work (for Windows) you first have to get the JNA Library at JAVA NATIVE ACCESS (JNA): Downloads or get it from maven

Look at the following code, which will get the pid of a (in this example windows) program (most of the code is actually debris to get a working java program going):

import com.sun.jna.*;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

static interface Kernel32 extends Library {

    public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);

    public int GetProcessId(Long hProcess);
}

public static void main(String[] args) {
    try {
        Process p;

        if (Platform.isWindows())
            p = Runtime.getRuntime().exec("cmd /C ping msn.de");
        else if (Platform.isLinux())
            p = Runtime.getRuntime().exec("cmd /C ping msn.de");

        System.out.println("The PID: " + getPid(p));

        int x = p.waitFor();
        System.out.println("Exit with exitcode: " + x);

    } catch (Exception ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public static int getPid(Process p) {
    Field f;

    if (Platform.isWindows()) {
        try {
            f = p.getClass().getDeclaredField("handle");
            f.setAccessible(true);
            int pid = Kernel32.INSTANCE.GetProcessId((Long) f.get(p));
            return pid;
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    } else if (Platform.isLinux()) {
        try {
            f = p.getClass().getDeclaredField("pid");
            f.setAccessible(true);
            int pid = (Integer) f.get(p);
            return pid;
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    else{}
    return 0;
}
}

Hope this helps, ;)...

波浪屿的海角声 2024-10-23 08:35:45

我过去使用您在这里建议的相同方法解决了这个问题:对于 Windows 使用 taskkill,对于 Unix 使用kill -9。

在 Windows 上,您可以通过从 Java 调用脚本(VBS 或 JS)或使用互操作性库之一(JaWin、Jintegra、Jinterop 等)来使用 WMI。

我认为这个解决方案并不像您担心的那么复杂。我认为不超过50行代码。

祝你好运。

I had solved such problem in past using the same method you are suggesting here: use taskkill for windows and kill -9 for Unix.

On windows you can use alternatively WMI by either invoking script (VBS or JS) from Java or using one of interoperability libraries (JaWin, Jintegra, Jinterop etc.)

I do not think that this solution is so complicated as you are afraid. I think it is not more than 50 code lines.

Good luck.

动次打次papapa 2024-10-23 08:35:45

对于使用 jna 3.5.1 的 Windows

try {
        Process p = Runtime.getRuntime.exec("notepad");

        Field f = p.getClass().getDeclaredField("handle");
        f.setAccessible(true);              
        long handLong = f.getLong(p);

            Kernel32 kernel = Kernel32.INSTANCE;

        WinNT.HANDLE handle = new WinNT.HANDLE();

        handle.setPointer(Pointer.createConstant(handLong));

        int pid = kernel.GetProcessId(handle);

        System.out.print(pid);
    } catch (Throwable e) {
}

For windows using jna 3.5.1

try {
        Process p = Runtime.getRuntime.exec("notepad");

        Field f = p.getClass().getDeclaredField("handle");
        f.setAccessible(true);              
        long handLong = f.getLong(p);

            Kernel32 kernel = Kernel32.INSTANCE;

        WinNT.HANDLE handle = new WinNT.HANDLE();

        handle.setPointer(Pointer.createConstant(handLong));

        int pid = kernel.GetProcessId(handle);

        System.out.print(pid);
    } catch (Throwable e) {
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文