Инструмент / метод Java для принудительного уничтожения дочернего процесса - PullRequest
14 голосов
/ 06 февраля 2011

Я ищу инструмент / пакет / библиотеку 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.

Ответы [ 3 ]

8 голосов
/ 17 мая 2011

Существует более простой способ сделать это с помощью Java JNA.

Это определенно работает для Windows и Linux, я предполагаю, что вы можете сделать то же самое и для других платформ.

Самая большая проблема обработки Java-процессов - это отсутствие метода для получения идентификатора процесса, запущенного с помощью untime.getRuntime (). Exec ().

Предполагая, что вы получили pid процесса, вы всегда можете запустить команду kill -9 в linux или использовать аналогичные способы для уничтожения процесса в windows.

Вот способ получения идентификатора процесса для linux (заимствован из платформы selenium :)), и с помощью JNA это также может быть сделано для окон (с использованием вызовов Windows API API).

Чтобы это работало (для Windows), вам сначала нужно получить библиотеку JNA по адресу JAVA NATIVE ACCESS (JNA): Загрузите или получить ее по maven

Посмотрите на следующий код, который получит pid программы (в этом примере Windows) (большая часть кода на самом деле является мусором для запуска работающей 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;
}
}

Надеюсь, это поможет,;) ...

2 голосов
/ 06 февраля 2011

В прошлом я решал эту проблему, используя тот же метод, который вы предлагаете здесь: используйте taskkill для windows и kill -9 для Unix.

В Windows вы также можете использовать WMI, либо вызывая скрипт (VBS или JS) из Java, либо используя одну из библиотек взаимодействия (JaWin, Jintegra, Jinterop и др.)

Я не думаю, что это решение настолько сложно, как вы боитесь. Я думаю, что это не более 50 строк кода.

Удачи.

1 голос
/ 19 февраля 2013

Для окон, использующих 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) {
}
...