Отправить Ctrl-C для обработки открытым с помощью Java

В ОС Windows.

Я запускаю подпроцесс через Runtime.getRuntime(). exec(); Я хочу отправить "ctrl-c" в процесс, чтобы остановить его.

Я сделал небольшой пример с Runtime.getRuntime(). exec ( "ping google.com -n 100000" ); Код можно найти там: http://pastebin.com/f6315063f

До сих пор я пытался отправить символ char '3' (ctrl-C) через Process outputStream.

Вот немного кода:

 cmd = re.exec("ping google.com -n 10000"); 
 out = new BufferedWriter (new OutputStreamWriter(cmd.getOutputStream()));
 input =  new BufferedReader (new  InputStreamReader(cmd.getInputStream()));


 char ctrlBreak = (char)3;
 //Different testing way to send the ctrlBreak;
 out.write(ctrlBreak);
 out.flush();
 out.write(ctrlBreak+"\n");
 out.flush();

Я не хочу убивать процесс, я просто хочу отправить сигнал Ctrl-C. Как я могу это сделать?

Ответы

Ответ 1

Я считаю, что Ctrl-C улавливается оболочкой и транслируется в сигнал (SIGINT), который отправляется в основной процесс (в этом случае ваш порожденный процесс).

Итак, я думаю, вам нужно будет получить идентификатор процесса, а затем отправить соответствующий сигнал этому процессу. Этот вопрос кажется очень похожим и указывает на различные ресурсы использования.

Ответ 2

После много-много испытаний я нашел решение, которое мне сейчас нравится. В основном, он работает следующим образом: 1. Получить идентификатор процесса процесса, который вы начали 2. Передайте этот PID в слегка измененную версию SendSignal.exe, которая отправляет Ctrl-C вместо Ctrl-Break

Оба шага не совсем прямолинейны, но почти. Для 1. вам нужно получить PID. Java не предоставляет никакого родного способа ее получения. Есть несколько тем, которые обсуждают, как это сделать. Я решил для одного, где вам нужно теперь имя (см. GetProcessIDs() в коде ниже).

Для 2. вам нужно иметь инструмент, который отправляет CTRL-C в заданный PID. Опять же, Java не делает этого. Существуют разные способы сделать это (например, использовать обертку на питоне или около того), но все они несколько сложны. Я нашел, что проще всего использовать файл .exe для выполнения задания. Для этого я изменил SendSingal.exe. Вы можете получить исходный код здесь: 1. Затем просто замените все вхождения "BREAK" (также строчными буквами) на "C" и перекомпилируйте.

Переименуйте exe в SendSignalC.exe и поместите его в подпапку ext\из которой вы запустите Java. Затем запустите код ниже и счастливо звоните, например. SendCTRLC.sendCtrlC( "howeveryourprogramiscall.exe" ).

/** 
 * Sends CTRL-C to running processes from Java (in Windows)
 * and ca get ProcessID(s) for a given process name.
 * IMPORTANT!
 * This function NEEDS SendSignalC.exe in the ext\ subdirectory.
 * @author Kai Goergen
 */

import java.io.*;
import java.util.*;

public class SendCTRLC() {


    /**
     * Get all PIDs for a given name and send CTRL-C to all
     * @param processName
     * @return
     */
    public static List<String> sendCTRLC(String processName) {
        // get all ProcessIDs for the processName
        List<String> processIDs = getProcessIDs(processName);
        System.out.println("" + processIDs.size() + " PIDs found for " + processName + ": " + processIDs.toString());
        for (String pid : processIDs) {
            // close it
            sendCTRLC(Integer.parseInt(pid));
        }
        return processIDs;
    }

    /**
     * Send CTRL-C to the process using a given PID
     * @param processID
     */
    public static void sendCTRLC(int processID) {
        System.out.println(" Sending CTRL+C to PID " + processID);
        try {
            Process p = Runtime.getRuntime().exec("cmd /c ext\\SendSignalC.exe " + processID);
            StreamGobbler.StreamGobblerLOGProcess(p);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Get List of PIDs for a given process name
     * @param processName
     * @return
     */
    public static List<String> getProcessIDs(String processName) {
        List<String> processIDs = new ArrayList<String>();
        try {
            String line;
            Process p = Runtime.getRuntime().exec("tasklist /v /fo csv");
            BufferedReader input = new BufferedReader
                    (new InputStreamReader(p.getInputStream()));
            while ((line = input.readLine()) != null) {
                if (!line.trim().equals("")) {
                    // Pid is after the 1st ", thus it argument 3 after splitting
                    String currentProcessName = line.split("\"")[1];
                    // Pid is after the 3rd ", thus it argument 3 after splitting
                    String currentPID = line.split("\"")[3];
                    if (currentProcessName.equalsIgnoreCase(processName)) {
                        processIDs.add(currentPID);
                    }
                }
            }
            input.close();
        }
        catch (Exception err) {
            err.printStackTrace();
        }
        return processIDs;

    }
}

PS: Мне бы хотелось приложить здесь SendSignalC.exe, но я не думаю, что мне разрешено. Во всяком случае, изменения просты и прямолинейны, если у вас есть работающий cpp-компилятор...

Ответ 3

Чтобы завершить работу, вы можете taskkill java с помощью этого кода:

Runtime.getRuntime().exec("taskkill /f /im java.exe");

Надеюсь, что эта помощь!

Ответ 4

Переключение на Java 9 и сохранить время, Process имеет pid собственности сейчас, обратитесь к документации здесь для подробностей. Вы можете легко убить другой процесс следующим образом:

long pid = process.pid();
Runtime.getRuntime().exec("kill " + pid);