2012-04-12 19 views
9

मैं बैच फ़ाइल शुरू करने के लिए जावा में Runtime.getRuntime()। Exec() कमांड का उपयोग कर रहा हूं जो बदले में विंडोज प्लेटफॉर्म के लिए एक और प्रक्रिया शुरू करता है।मैं जावा से एक प्रक्रिया पेड़ को कैसे समाप्त करूं?

javaw.exe(Process1) 
|___xyz.bat(Process2) 
     |___javaw.exe(Process3) 

Runtime.getRuntime()। कार्यकारी() एक प्रक्रिया वस्तु जो एक विधि को नष्ट किया है देता है, लेकिन जब मैं नष्ट() का उपयोग, यह केवल xyz.bat को मारता है और बैच फ़ाइल के उप प्रक्रिया झूलने छोड़ देता है ।

क्या बैच प्रक्रिया के साथ शुरू होने वाले प्रक्रिया पेड़ को रूट करने के लिए जावा में एक साफ तरीका है?

* मैं किसी भी कस्टम लाइब्रेरी का उपयोग नहीं कर सकता \ जाओ मुद्दा

+0

क्या मैं पूछ सकता हूं कि कस्टम लाइब्रेरी आवश्यकता क्यों नहीं है? मेरे अनुभव में, ऐसी आवश्यकताओं के लिए आमतौर पर मौजूदा के लिए बहुत ही खराब कारण होता है, और लाइब्रेरी की आवश्यकता के कारण स्पष्टीकरण के साथ परक्राम्य हो सकता है (इस मामले में, जावा प्लेटफ़ॉर्म से अनुपलब्ध एक आवश्यक सुविधा, अर्थात् गणना करने का एक तरीका अभिभावक प्रक्रिया के उपप्रोसेसर)। – Jules

उत्तर

10

यह मानक जावा एपीआई का उपयोग संभव नहीं है (एक अद्यतन है कि इस में परिवर्तन के लिए पोस्ट के अंत में संपादित करें देखें)। आपको कुछ विविधता के कुछ देशी कोड की आवश्यकता होगी। JNA का उपयोग करना, मैं कोड है कि इस तरह दिखता है उपयोग किया है:

public class Win32Process 
{ 
    WinNT.HANDLE handle; 
    int pid; 

    Win32Process (int pid) throws IOException 
    { 
     handle = Kernel32.INSTANCE.OpenProcess ( 
       0x0400| /* PROCESS_QUERY_INFORMATION */ 
       0x0800| /* PROCESS_SUSPEND_RESUME */ 
       0x0001| /* PROCESS_TERMINATE */ 
       0x00100000 /* SYNCHRONIZE */, 
       false, 
       pid); 
     if (handle == null) 
      throw new IOException ("OpenProcess failed: " + 
        Kernel32Util.formatMessageFromLastErrorCode (Kernel32.INSTANCE.GetLastError())); 
     this.pid = pid; 
    } 

    @Override 
    protected void finalize() throws Throwable 
    { 
     Kernel32.INSTANCE.CloseHandle (handle); 
    } 

    public void terminate() 
    { 
     Kernel32.INSTANCE.TerminateProcess (handle, 0); 
    } 

    public List<Win32Process> getChildren() throws IOException 
    { 
     ArrayList<Win32Process> result = new ArrayList<Win32Process>(); 
     WinNT.HANDLE hSnap = KernelExtra.INSTANCE.CreateToolhelp32Snapshot (KernelExtra.TH32CS_SNAPPROCESS, new DWORD(0)); 
     KernelExtra.PROCESSENTRY32.ByReference ent = new KernelExtra.PROCESSENTRY32.ByReference(); 
     if (!KernelExtra.INSTANCE.Process32First (hSnap, ent)) return result; 
     do { 
      if (ent.th32ParentProcessID.intValue() == pid) result.add (new Win32Process (ent.th32ProcessID.intValue())); 
     } while (KernelExtra.INSTANCE.Process32Next (hSnap, ent)); 
     Kernel32.INSTANCE.CloseHandle (hSnap); 
     return result; 
    } 

}

इस कोड को निम्नलिखित JNA घोषणाओं कि मानक JNA पुस्तकालय में शामिल नहीं हैं उपयोग करता है:

public interface KernelExtra extends StdCallLibrary { 

    /** 
    * Includes all heaps of the process specified in th32ProcessID in the snapshot. To enumerate the heaps, see 
    * Heap32ListFirst. 
    */ 
    WinDef.DWORD TH32CS_SNAPHEAPLIST = new WinDef.DWORD(0x00000001); 

    /** 
    * Includes all processes in the system in the snapshot. To enumerate the processes, see Process32First. 
    */ 
    WinDef.DWORD TH32CS_SNAPPROCESS = new WinDef.DWORD(0x00000002); 

    /** 
    * Includes all threads in the system in the snapshot. To enumerate the threads, see Thread32First. 
    */ 
    WinDef.DWORD TH32CS_SNAPTHREAD = new WinDef.DWORD(0x00000004); 

    /** 
    * Includes all modules of the process specified in th32ProcessID in the snapshot. To enumerate the modules, see 
    * Module32First. If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds. 
    */ 
    WinDef.DWORD TH32CS_SNAPMODULE = new WinDef.DWORD(0x00000008); 

    /** 
    * Includes all 32-bit modules of the process specified in th32ProcessID in the snapshot when called from a 64-bit 
    * process. This flag can be combined with TH32CS_SNAPMODULE or TH32CS_SNAPALL. If the function fails with 
    * ERROR_BAD_LENGTH, retry the function until it succeeds. 
    */ 
    WinDef.DWORD TH32CS_SNAPMODULE32 = new WinDef.DWORD(0x00000010); 

    /** 
    * Includes all processes and threads in the system, plus the heaps and modules of the process specified in th32ProcessID. 
    */ 
    WinDef.DWORD TH32CS_SNAPALL  = new WinDef.DWORD((TH32CS_SNAPHEAPLIST.intValue() | 
      TH32CS_SNAPPROCESS.intValue() | TH32CS_SNAPTHREAD.intValue() | TH32CS_SNAPMODULE.intValue())); 

    /** 
    * Indicates that the snapshot handle is to be inheritable. 
    */ 
    WinDef.DWORD TH32CS_INHERIT  = new WinDef.DWORD(0x80000000); 

    /** 
    * Describes an entry from a list of the processes residing in the system address space when a snapshot was taken. 
    */ 
    public static class PROCESSENTRY32 extends Structure { 

     public static class ByReference extends PROCESSENTRY32 implements Structure.ByReference { 
      public ByReference() { 
      } 

      public ByReference(Pointer memory) { 
       super(memory); 
      } 
     } 

     public PROCESSENTRY32() { 
      dwSize = new WinDef.DWORD(size()); 
     } 

     public PROCESSENTRY32(Pointer memory) { 
      useMemory(memory); 
      read(); 
     } 

     /** 
     * The size of the structure, in bytes. Before calling the Process32First function, set this member to 
     * sizeof(PROCESSENTRY32). If you do not initialize dwSize, Process32First fails. 
     */ 
     public WinDef.DWORD dwSize; 

     /** 
     * This member is no longer used and is always set to zero. 
     */ 
     public WinDef.DWORD cntUsage; 

     /** 
     * The process identifier. 
     */ 
     public WinDef.DWORD th32ProcessID; 

     /** 
     * This member is no longer used and is always set to zero. 
     */ 
     public BaseTSD.ULONG_PTR th32DefaultHeapID; 

     /** 
     * This member is no longer used and is always set to zero. 
     */ 
     public WinDef.DWORD th32ModuleID; 

     /** 
     * The number of execution threads started by the process. 
     */ 
     public WinDef.DWORD cntThreads; 

     /** 
     * The identifier of the process that created this process (its parent process). 
     */ 
     public WinDef.DWORD th32ParentProcessID; 

     /** 
     * The base priority of any threads created by this process. 
     */ 
     public WinDef.LONG pcPriClassBase; 

     /** 
     * This member is no longer used, and is always set to zero. 
     */ 
     public WinDef.DWORD dwFlags; 

     /** 
     * The name of the executable file for the process. To retrieve the full path to the executable file, call the 
     * Module32First function and check the szExePath member of the MODULEENTRY32 structure that is returned. 
     * However, if the calling process is a 32-bit process, you must call the QueryFullProcessImageName function to 
     * retrieve the full path of the executable file for a 64-bit process. 
     */ 
     public char[] szExeFile = new char[WinDef.MAX_PATH]; 
    } 


    // the following methods are in kernel32.dll, but not declared there in the current version of Kernel32: 

    /** 
    * Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes. 
    * 
    * @param dwFlags 
    * The portions of the system to be included in the snapshot. 
    * 
    * @param th32ProcessID 
    * The process identifier of the process to be included in the snapshot. This parameter can be zero to indicate 
    * the current process. This parameter is used when the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, 
    * TH32CS_SNAPMODULE32, or TH32CS_SNAPALL value is specified. Otherwise, it is ignored and all processes are 
    * included in the snapshot. 
    * 
    * If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last 
    * error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from opening them. 
    * 
    * If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the 
    * last error code is ERROR_PARTIAL_COPY (299). 
    * 
    * @return 
    * If the function succeeds, it returns an open handle to the specified snapshot. 
    * 
    * If the function fails, it returns INVALID_HANDLE_VALUE. To get extended error information, call GetLastError. 
    * Possible error codes include ERROR_BAD_LENGTH. 
    */ 
    public WinNT.HANDLE CreateToolhelp32Snapshot(WinDef.DWORD dwFlags, WinDef.DWORD th32ProcessID); 

    /** 
    * Retrieves information about the first process encountered in a system snapshot. 
    * 
    * @param hSnapshot A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function. 
    * @param lppe A pointer to a PROCESSENTRY32 structure. It contains process information such as the name of the 
    * executable file, the process identifier, and the process identifier of the parent process. 
    * @return 
    * Returns TRUE if the first entry of the process list has been copied to the buffer or FALSE otherwise. The 
    * ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no processes exist or the snapshot 
    * does not contain process information. 
    */ 
    public boolean Process32First(WinNT.HANDLE hSnapshot, KernelExtra.PROCESSENTRY32.ByReference lppe); 

    /** 
    * Retrieves information about the next process recorded in a system snapshot. 
    * 
    * @param hSnapshot A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function. 
    * @param lppe A pointer to a PROCESSENTRY32 structure. 
    * @return 
    * Returns TRUE if the next entry of the process list has been copied to the buffer or FALSE otherwise. The 
    * ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no processes exist or the snapshot 
    * does not contain process information. 
    */ 
    public boolean Process32Next(WinNT.HANDLE hSnapshot, KernelExtra.PROCESSENTRY32.ByReference lppe); 


} 

आप फिर बच्चों की सूची प्राप्त करने के लिए 'getChildren()' विधि का उपयोग कर सकते हैं, माता-पिता को समाप्त कर सकते हैं, और फिर बच्चों को फिर से समाप्त कर सकते हैं।

मेरा मानना ​​है कि आप प्रतिबिंब का उपयोग करके java.lang.Process के पीआईडी ​​को अतिरिक्त कर सकते हैं (मैंने यह नहीं किया है, हालांकि, मैंने Win32 API का उपयोग करके प्रक्रियाओं को स्वयं बनाने के लिए स्विच किया ताकि मैं इसके ऊपर अधिक नियंत्रण रख सकूं)।

तो उसे एक साथ रखते हैं, तो आप की तरह कुछ आवश्यकता होगी:

int pid = (some code to extract PID from the process you want to kill); 
Win32Process process = new Win32Process(pid); 
kill(process); 

public void kill(Win32Process target) throws IOException 
{ 
    List<Win32Process> children = target.getChildren(); 
    target.terminateProcess(); 
    for (Win32Process child : children) kill(child); 
} 

संपादित

ऐसा लगता है कि जावा एपीआई के इस विशेष कमी जावा 9. में तय की जा रही है की पूर्वावलोकन देखें जावा 9 प्रलेखन here (यदि सही पृष्ठ लोड नहीं होता है, तो आपको java.lang.ProcessHandle इंटरफ़ेस को देखने की आवश्यकता है)। उपरोक्त प्रश्न की आवश्यकता के लिए, कोड अब कुछ इस तरह दिखेगा:

Process child = ...; 
kill (child.toHandle()); 

public void kill (ProcessHandle handle) 
{ 
    handle.descendants().forEach((child) -> kill(child)); 
    handle.destroy(); 
} 

(ध्यान दें कि यह परीक्षण नहीं किया है - मैं जावा से 9 अभी तक परिवर्तित नहीं किया है, लेकिन सक्रिय रूप से इसके बारे में पढ़ रहा हूँ)

0

आप JDK का उपयोग कर खिड़कियों के लिए एक प्रक्रिया पेड़ को नहीं मार सकते हैं दर-पारित करने के लिए बैच फ़ाइल से छुटकारा। आपको WinAPI पर भरोसा करने की आवश्यकता है। आपको मूल आदेश या जेएनआई पुस्तकालयों का सहारा लेना होगा, जिनमें से सभी मंच-निर्भर हैं और एक शुद्ध जावा समाधान से अधिक जटिल होंगे।

एक नमूना लिंक JNI Example

+0

दुर्भाग्य से मैं किसी भी बाहरी या कस्टम पुस्तकालयों का उपयोग नहीं कर सकता। हालांकि, मैं बैच फ़ाइल को बदल सकता हूं। क्या जावा से Process.destroy() द्वारा भेजे गए बैच में टर्म सिग्नल पकड़ने का कोई तरीका है? और फिर उप-प्रक्रिया को मारने के लिए इसका इस्तेमाल करें? – srami

+0

आप बैच फ़ाइल का उपयोग कर प्रक्रियाओं का प्रबंधन कर सकते हैं। प्रबंधन के लिए उपलब्ध कई विकल्पों के लिए लिंक के माध्यम से जाएं। http://www.robvanderwoude.com/processes.php – Phani

+0

मुझे विश्वास नहीं है कि विंडोज बैच फ़ाइल को इस तरह के सिग्नल को पकड़ने का कोई तरीका है - जावा मूल रूप से टर्मिनेट प्रोसेस का उपयोग करता है, जो सीधे बिना किसी भेजने के प्रक्रिया को मारता है पहले इसे संकेत। इसके अलावा, यदि कोई बाल प्रक्रिया वर्तमान में चल रही है, तो बैच फ़ाइल को इसके अलावा कुछ और करने से पहले बाहर निकलने के लिए इंतजार करना होगा, और जावा प्रक्रिया को समाप्त करने के लिए जावा का कोई तरीका नहीं है। यदि आप ऐसा करना चाहते हैं तो आपको बाहरी पुस्तकालयों का उपयोग करना होगा। – Jules

1

एक वैकल्पिक समाधान, यदि आप बाल प्रक्रिया के साथ-साथ बैच फ़ाइल को नियंत्रित करते हैं, तो बच्चे की प्रक्रिया थ्रेड बनाने, सर्वरसॉकेट खोलने, उसके कनेक्शन के लिए सुनना और System.exit() को कॉल करना होगा। अगर इसे इस पर एक सही पासवर्ड प्राप्त होता है।

यदि आपको कई एक साथ उदाहरण की आवश्यकता है तो जटिलताएं हो सकती हैं; उस समय आपको उन्हें पोर्ट नंबर आवंटित करने के कुछ तरीके की आवश्यकता होगी।

0

यहां एक और विकल्प है। अपनी बल्ले स्क्रिप्ट निष्पादित करने के लिए इस शक्तिशक्ति स्क्रिप्ट का उपयोग करें। जब आप पेड़ को मारना चाहते हैं, तो अपनी पावरहेल स्क्रिप्ट की प्रक्रिया को समाप्त करें और यह स्वचालित रूप से टास्ककिल को इसके उप-प्रोसेस पर निष्पादित करेगा। मैंने इसे टास्ककिल को दो बार बुलाया है क्योंकि कुछ मामलों में यह पहली कोशिश नहीं करता है।

Param(
    [string]$path 
) 

$p = [Diagnostics.Process]::Start("$path").Id 

try { 
    while($true) { 
     sleep 100000 
    } 
} finally { 
    taskkill /pid $p 
    taskkill /pid $p 
} 
0

जावा 9 के साथ, मुख्य प्रक्रिया को मारने से पूरे प्रक्रिया के पेड़ को मार दिया जाता है। आप कुछ इस तरह कर सकता है:

Process ptree = Runtime.getRuntime().exec("cmd.exe","/c","xyz.bat"); 
// wait logic 
ptree.destroy(); 

कृपया इस blog पर एक नज़र डालें और प्रक्रिया पेड़ उदाहरण के साथ डील की जाँच करें।

संबंधित मुद्दे