19

Under Windows OS.

I start a sub-process via a Runtime.getRuntime().exec(); I want to send a "ctrl-c" to the process to stop it.

I did a small example, with Runtime.getRuntime().exec("ping google.com -n 100000"); The code can be found there : http://pastebin.com/f6315063f

So far, I tried to send the char '3' (ctrl-C character) via Process outputStream.

Here is a bit of code:

 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();

I don't want to kill the process, I just want to send a Ctrl-C signal. How can I do that?

Nettogrof
  • 2,116
  • 2
  • 15
  • 22

4 Answers4

8

I believe Ctrl-C is caught by the shell and translated into a signal (SIGINT) which is sent to the underlying process (in this case your spawned process).

So I think you'll need to get the process id and then send the appropriate signal to that process. This question appears to be very similar and points to various resources of use.

Community
  • 1
  • 1
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
3

After lots and lots of trials, I found a solution that I like now. Basically, it works like this: 1. Get the Process ID of the process that you started 2. Pass this PID to a slightly modified version of SendSignal.exe, which sends Ctrl-C instead of Ctrl-Break

Both steps are not completely straight forward, but nearly. For 1. you need to get the PID. Java does not provide any native way to get it. There are a number of threads discussing about how to do that best. I decided for one where you need to now the name (see getProcessIDs() in the code below).

For 2. you need to have a tool that sends CTRL-C to a given PID. Again, Java does not do this. There are different ways to do it (e.g. using a wrapper in python or so), but all of them are somewhat complicated. I found the easiest one is to use a .exe-File to do the job. For this, I modified SendSingal.exe. You can get the sourcecode here: 1. Then, simply replace all occurences of "BREAK" (also in lowercase letters) by "C" and recompile.

Rename the exe to SendSignalC.exe and put it in a subfolder ext\ of where you start Java. Then run the code below and happily call e.g. 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's argument 3 after splitting
                    String currentProcessName = line.split("\"")[1];
                    // Pid is after the 3rd ", thus it's 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: I would love to attach SendSignalC.exe here, but I don't think that I'm allowed to. Anyhow, the changes are simple and straight-forward if you have a running cpp-compiler...

Kai
  • 77
  • 1
  • 2
  • @soulseekah - StreamGobbler.StreamGobblerLOGProcess(p); package not found. I want to quit an service which is running over cmd, so never quit need to press cntrol + c or any other machnism, please share if you know anything about it – Shubham Jain Sep 10 '18 at 18:33
2

Switch to Java 9 and save your time, Process has pid property now, check the documentation here for details. You can easily kill another process like this:

long pid = process.pid();
Runtime.getRuntime().exec("kill " + pid);
user1079877
  • 9,008
  • 4
  • 43
  • 54
0

To terminate you can taskkill java with this code:

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

Hope this help!

Huy Hóm Hỉnh
  • 597
  • 7
  • 18