2009-12-02 18 views
14

In Windows OS.Invia Ctrl-C per processo aperto da Java

inizio un sottoprocesso tramite un Runtime.getRuntime() exec().; Voglio inviare un "ctrl-c" al processo per fermarlo.

Ho fatto un piccolo esempio, con Runtime.getRuntime() exec ("ping google.com -n 100000."); Il codice può essere trovato qui: http://pastebin.com/f6315063f

Finora, ho provato a inviare il carattere "3" (carattere Ctrl-C) tramite Process outputStream.

Ecco un po 'di codice:

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

Non voglio uccidere il processo, voglio solo mandare un segnale Ctrl-C. Come posso farlo?

+0

In definitiva, cosa stai cercando di ottenere? –

+0

Realizza un wrapper attorno a un vecchio DOS/windows3.L'applicazione 1/win95 – Nettogrof

+0

dovrebbe funzionare ma dovresti inviare un'interruzione solo una volta, facendolo due volte ovviamente ucciderebbe il processo principale. –

risposta

6

Credo che Ctrl-C sia catturato dalla shell e tradotto in un segnale (SIGINT) che viene inviato al processo sottostante (in questo caso il processo spawn).

Quindi penso che sarà necessario per ottenere l'ID di processo e quindi inviare il segnale adeguato a tale processo. This question sembra molto simile e indica varie risorse di utilizzo.

+0

Ho visto quella domanda ma SendSignal invia solo un segnale di ctrl-break. – Nettogrof

+0

Quindi penso che sia necessario trovare l'id di processo e inviare SIGINT tramite (forse) una funzione POSIX o simile. –

5

Dopo un sacco di prove, ho trovato una soluzione che mi piace ora. In sostanza, funziona così: 1. Ottenere l'ID di processo del processo che è stato avviato 2. passare questo PID per una versione leggermente modificata di SendSignal.exe, che invia Ctrl-C invece di Ctrl-Break

Entrambi i passaggi non sono completamente semplici, ma quasi. Per 1. è necessario ottenere il PID. Java non fornisce alcun modo nativo per ottenerlo. Ci sono diversi thread che discutono su come fare meglio. Ho deciso per uno dove è necessario ora il nome (vedi getProcessIDs() nel codice qui sotto).

Per 2. è necessario disporre di uno strumento che invia CTRL-C a un dato PID. Ancora una volta, Java non lo fa. Esistono diversi modi per farlo (per esempio usando un involucro in pitone o così), ma tutti sono piuttosto complicato. Ho trovato il più semplice è quello di utilizzare un file .exe per fare il lavoro. Per questo, ho modificato SendSingal.exe. È possibile ottenere il codice sorgente qui: 1. Quindi, semplicemente sostituire tutte le occorrenze di "BREAK" (anche in lettere minuscole) con "C" e ricompilare.

Rinominare l'exe in SendSignalC.exe e inserirlo in una sottocartella ext \ di dove si avvia Java. Quindi esegui il codice di seguito e chiama con piacere per es. 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: Mi piacerebbe attaccare SendSignalC.exe qui, ma non credo che mi sia permesso. In ogni caso, i cambiamenti sono semplici e diretto se si dispone di un running cpp-compiler ...

+0

Questo è molto interessante. Grazie per la condivisione. – soulseekah

0

Per terminare è possibile taskkilljava con questo codice:

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

Spero che questo aiuto!

Problemi correlati