2016-07-01 3 views
1

명령 창이 실행되는 응용 프로그램이 있습니다. 사용자가 /quit을 입력 할 때이를 감지하고 해당 quit() 메서드를 실행하는 Scanner이 있습니다.콘솔 닫을 때 호출 방법 (Java)

완벽하게 작동하지만 사용자가 /quit을 입력하지 않고 콘솔을 닫고 여전히 quit()을 실행하는지 확인하는 방법이 있습니까?

+1

A [종료 후크 추가] (https://docs.oracle.com/javase/7/docs/ api/java/lang/Runtime.html # addShutdownHook (java.lang.Thread))? – shmosel

답변

1

종료 훅을 사용하십시오. 여전히 100 % 보장받을 수는 없지만 시스템 종료를 시도하는 데 가장 좋은 방법입니다. 일반적으로 셧다운 훅에서는 절대 최소가 가능해야합니다. 리소스를 닫거나, 몇개의 로깅 문장이나 printstatements를 삭제하되 오래 걸리지는 마십시오.

로버트가 여기에있는 대답 Detecting when a Java application closes을 복사하여 약간 수정했습니다. 이 코드는 quit()를 호출 할 권한이있는 어딘가에 두어야합니다. 이 메시지는 한 번만 호출해야하지만 전체 프로세스의 초기에 호출해야합니다.

Runtime.getRuntime().addShutdownHook(new Thread() { 

    @Override 
    public void run() { 
     quit(); 
    } 

}); 

종료 훅이 무엇을하고 있는지에 대한 자세한 내용은이 질문을 참조 : Useful example of a shutdown hook in Java?

종료 후크가 및 호출되지 않습니다시기에 대한 자세한 내용은이 질문의 허용 대답을 참조하십시오 shutdown hook vs finalizer method

quit() TL을 사용하여 작업해야하는 시간에 대한 정보는이 질문을 참조하십시오. How long does the JVM allow shutdown hooks to run before calling halt?

+0

흠, 창 명령 프롬프트를 닫으면 아무 것도하기 전에 닫히는 것처럼 보입니다 ... 거기에'Thread.sleep()'을 넣으면 즉시 닫힙니다. 나는 무엇이든지하기 전에 다른 대답이 있는지 볼 것입니다. 그래도 고마워! = D @Jeutnarg – criticaldiamonds

+0

OS가 프로세스를 죽이는 방법에 따라 아무 것도 할 수있는 기회가 생길 수도 있고 그렇지 않을 수도 있습니다. 이것이 셧다운 후크가 신뢰할 수없는 이유입니다. –

+0

@criticaldiamonds 당신의 공손함이 나를 자극했습니다 - 제 다른 대답을보십시오 – Jeutnarg

0

이것은 프로를 잡는 데 더 위험하지만 더 강력한 방법입니다 그램 출구. 의도적으로이 방법을 깨뜨릴 수있는 몇 가지 방법이 있으며, OS가 우연히도 깨뜨릴 수있는 여지가 있습니다. 그래서 내가 '위험한'이라고 말한 것이다.

하나의 클래스 인 보디 가드 (Bodyguard)가 자신의 프로세스 ID를 파악한 다음 입력 된 processid로 RealProgram을 실행합니다. 보디가 드는 RealProgram이 종료 될 때까지 대기 한 다음 종료합니다. 한편, RealProgram은 보디 가드의 프로세스가 계속 실행 중인지 확인하고 검사합니다. 보디 가드가 사망 한 것으로 확인되면 주 루프를 종료하고 종료하기 전에 quit()을 호출합니다.

Windows 10에서 Java 8을 실행하고 Eclipse 디버거에서 보디 가드를 죽이는 방법을 테스트했습니다. 보디 가드가 사망하면 quit()를 호출 한 후 RealProgram이 종료됩니다. RealProgram이 죽으면 보디 가드도 종료됩니다.

코드를 가지고 놀고 싶을 것이므로 필자와 같은 디버깅 요소 중 일부를 남겨 두었습니다.

I 제공 : 두 번째 JVM 윈도우에서 실행중인 프로세스를 얻는 방법에

  • this external page을 시작하는 방법에 대한 코드와 프로세스 ID
  • this question을 얻기위한 코드

    보디 가드 등급 :

    package so_38154756; 
    
    import java.lang.reflect.InvocationTargetException; 
    
    public class Bodyguard { 
    
        public static void main(String[] args){ 
         Bodyguard lamb = new Bodyguard(); 
         lamb.initiateSacrifice(); 
        } 
    
        private void initiateSacrifice() { 
         try{ 
          int ownPid = getPID(); 
          runRealProgram(ownPid); 
         } catch(Exception e){ 
          System.out.println("Sorry, this isn't working."); 
         } 
        } 
    
        private int getPID() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { 
         java.lang.management.RuntimeMXBean runtime = java.lang.management.ManagementFactory.getRuntimeMXBean(); 
         java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm"); 
         jvm.setAccessible(true); 
         sun.management.VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); 
         java.lang.reflect.Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); 
         pid_method.setAccessible(true); 
         int pid = (Integer) pid_method.invoke(mgmt); 
         return pid; 
        } 
    
        private void runRealProgram(int ownPid) throws Exception { 
         String separator = System.getProperty("file.separator"); 
         String classpath = System.getProperty("java.class.path"); 
         String path = System.getProperty("java.home") + separator + "bin" + separator + "java"; 
         ProcessBuilder processBuilder = new ProcessBuilder(path, "-cp", classpath, RealProgram.class.getName(), Integer.valueOf(ownPid).toString()); 
         Process process = processBuilder.start(); 
         process.waitFor();//will wait forever, but will close when the RealProgram closes 
        } 
    
    } 
    

    과 RealProgram 클래스 :

    package so_38154756; 
    
    import java.io.BufferedReader; 
    import java.io.File; 
    import java.io.FileNotFoundException; 
    import java.io.InputStreamReader; 
    import java.io.PrintWriter; 
    import java.util.regex.Pattern; 
    
    public class RealProgram { 
    
        private Integer bodyguardPID; 
        private PrintWriter writer; 
    
        public RealProgram(Integer bodyguardPID, PrintWriter writer) { 
         this.bodyguardPID = bodyguardPID; 
         this.writer = writer; 
        } 
    
        public static void main(String[] args){ 
         Integer sacrificialPID = Integer.parseInt(args[0]); 
         try { 
          PrintWriter writer = new PrintWriter(new File("output.txt")); 
          RealProgram rp = new RealProgram(sacrificialPID, writer); 
          writer.println("Past Constructor"); 
          rp.checkToSeeIfBodyguardLives(); 
          writer.println("Bodyguard had died"); 
          writer.close();//yes, yes, this could be slightly prettier with Java 8's try-with-resources 
         } catch (FileNotFoundException e) { 
          e.printStackTrace(); 
         } 
        } 
    
        private void checkToSeeIfBodyguardLives() { 
         while(true){ 
          try { Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//I wait because I was debugging - you may find it wise to not wait 
          //do whatever it is you're doing 
          if(!isBodyguardAlive()){ 
           quit(); 
           break; 
          } 
         } 
        } 
    
        private boolean isBodyguardAlive() { 
         try { 
          String process; 
          Pattern pattern = Pattern.compile(".*\\\""+bodyguardPID+"\\\".*");//Windows - have tested 
          //you'll have to figure out your own different pattern for linux - possible source for editing 
          writer.println("Searching for PID of "+bodyguardPID); 
          //Process p = Runtime.getRuntime().exec("ps -few"); - Linux - haven't tested - again, possible source for editing 
          Process p = Runtime.getRuntime().exec(System.getenv("windir") +"\\system32\\"+"tasklist.exe /fo csv /nh");//Windows - have tested 
          BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); 
          while ((process = input.readLine()) != null) { 
           if(pattern.matcher(process).matches()){ 
            return true; 
           } 
          } 
          input.close(); 
         } catch (Exception err) { 
          err.printStackTrace(); 
         } 
         return false; 
        } 
    
        private void quit(){ 
         writer.println("Detected Bodyguard has died"); 
        } 
    } 
    
  • 관련 문제