Java how to stop shell script launched previously

2019-08-12 19:46发布

问题:

I've created a server program which, when it receives some commands, executes some actions. I'd like when it receives the command "android" (which happens when a client connects from an android device) that my server launches a shell script and when the client disconnects I'd like it to stop the execution of this script.

Also, when a web browser clients connects and send the command "browser" the server would launch an other script.

Those two scripts can't be used at the same time because they use the same resources. That's why I need to stop them when a client disconnects (I'm aware that I can't have the two types of clients connected at the same time).

For now, I've been able to launch the scripts, but not to stop them. Here is the code of my run method in the server :

@Override
public void run() {
    try {
        BufferedReader ins = new BufferedReader(new InputStreamReader(soc.getInputStream()));

        Runtime r = Runtime.getRuntime();
        Process p = null;

        int i = 0;
        while (i < 1) {
            String request = ins.readLine();
            if (request == null || request.equals("close")) {
                p.destroy();
                System.out.println("The child was destroyed? "+p.exitValue());
                i++;
            }
            else {
                if (request.equals("android")) {
                    p = r.exec("sh /home/pi/test-raspicamsrc.sh &");
                }
                else if (request.equals("browser")) {
                    p = r.exec("sh /home/pi/test-http-launch.sh &");
                }
                else if (request.equals("left")) {
                    serialPort.writeBytes("4".getBytes());//Write data to port
                }
                else if (request.equals("right")) {
                    serialPort.writeBytes("6".getBytes());
                }
                else if (request.equals("stop")) {
                    serialPort.writeBytes("5".getBytes());
                }
                else if (request.equals("forward")) {
                    serialPort.writeBytes("8".getBytes());
                }
                else if (request.equals("backward")) {
                    serialPort.writeBytes("2".getBytes());
                }
                else {
                    System.out.println("Unknown command");
                }
            }
        }
        ins.close();
        soc.close();
        // We always stop the car in the end.
        serialPort.writeBytes("5".getBytes());
    }

The first time I disconnect an android device, the output of p.exitValue() is 143, and the script keeps executing. And after, if I connect one more time with the android client it doesn't seem to launch the script again (which is a good thing, I don't know why or maybe it does launch it but since the resource is already in use, it closes very quickly) and when I disconnect this new client p.exitValue() returns 0. Which is a normal thing since the process doesn't exist. But during this time the process of the first script launched keeps running.

I'd like to know why my command p.destroy() doesn't kill my script process. I think it could be because it stops the sh processes but not the process of my script (two different process) A bit like here java Process stop entire process tree

I hope there is a way to solve this problem, thank you ! :)

回答1:

you can check that your script is running or not in the server by following command.

ps -efw | grep 'process_name'

Now to stop your script from java program you can execute following command.

pkill -9 -f 'test-raspicamsrc.sh'

pkill command is used to kill the process by providing process pattern. If you want to kill your firefox application without pid you can execute like below.

pkill -9 -f 'firefox'



回答2:

Ok I've found how to make it work. Actually I had to use pkill but with the name of the process of the command executed in my script. Furthermore I had to change my way of executing commands in Java. Because launching pkill -9 -f 'gst-launch-1.0' in the shell stopped the script correctly but in the java code killProcess = r.exec("pkill -9 -f 'gst-launch-1.0'"); was uneffective. So I changed my way of executing shell command by this way : killProcess = r.exec(new String[]{"bash","-c","pkill -9 -f 'gst-launch-1.0'"}); (according to this topic : Want to invoke a linux shell command from Java)

So here is my working code :

@Override
    public void run() {
        try {
            BufferedReader ins = new BufferedReader(new InputStreamReader(soc.getInputStream()));

            Runtime r = Runtime.getRuntime();
            Process videoProcess = null;
            Process killProcess = null;
            boolean android = false;

            int i = 0;
            while (i < 1) {
                String request = ins.readLine();

                if (request == null || request.equals("close")) {
                    if (android) {
                        killProcess = r.exec(new String[]{"bash","-c","pkill -9 -f 'gst-launch-1.0'"});
                    }
                    else {
                        killProcess = r.exec(new String[]{"bash","-c","pkill -9 -f 'http-launch'"});
                    }
                    i++;
                }
                else {
                    if (request.equals("android")) {
                        videoProcess = r.exec(new String[]{"bash","-c","sh /home/pi/test-raspicamsrc.sh"});
                        android = true;
                    }
                    else if (request.equals("browser")) {
                        videoProcess = r.exec(new String[]{"bash","-c","sh /home/pi/test-http-launch.sh"});
                        android = false;
                    }
                    else if (request.equals("left")) {
                        serialPort.writeBytes("4".getBytes());//Write data to port
                    }
                    else if (request.equals("right")) {
                        serialPort.writeBytes("6".getBytes());
                    }
                    else if (request.equals("stop")) {
                        serialPort.writeBytes("5".getBytes());
                    }
                    else if (request.equals("forward")) {
                        serialPort.writeBytes("8".getBytes());
                    }
                    else if (request.equals("backward")) {
                        serialPort.writeBytes("2".getBytes());
                    }
                    else {
                        System.out.println("Unknown command");
                    }
                }
            }
            ins.close();
            soc.close();
            // We always stop the car in the end.
            serialPort.writeBytes("5".getBytes());

        }
        catch (IOException e) {
            System.out.println("Error input/output while initializing the server (Port 6020 may already be in use)");
        }
    }