Отправить 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);