轉載請請在頁首注明作者與出處
一:問題由史
今天遇到一個問題,就是在實現自動化災備的時候,發現原有死掉的程序沒有完全關閉,當然這都不是本文的重點,重點是這個時候,我得把它完全關閉,所以才有了這篇文章。
二:基礎知識
2.1:java要怎么實現
java可以獲取並刪除JAVA虛擬機啟動的應用,但是卻並沒有提供API獲取操作系統中其它的進程的API。
但是java可以執行操作系統的腳本命令。
2.2:根據端口查找進程
windows中有這樣的命令
netstat -ano 查看操作系統所有占用端口的進程
netstat -ano | findstr "8080" 獲取占用了80端口的進程
得到的結果如下
TCP 127.0.0.1:51846 127.0.0.1:5037 TIME_WAIT 0 TCP 127.0.0.1:51847 127.0.0.1:5037 TIME_WAIT 0 UDP 0.0.0.0:4500 *:* 444 UDP 0.0.0.0:5355 *:* 1232
可以看到TCP/UPD是所使用的協議,后面的是綁定IP與端口,最后一列,是占用的進程號(pid)。
2.3:根據進程號刪除進程
再來看一條命令
taskkill /pid 123
我們可以關閉進程號為123的進程,當然,我試上面的這條命令的時候,系統提示無法終止這個進程,那我們可以加一個/F,如下,就能強行關閉。
taskkill /F /pid 123
三:java實現,支持一次性殺死多個端口
之前有說過,java可以執行操作系統的腳本,不論是什么操作,系統,那么我們就可以用這個方法,來直接執行這些命令來達到相應的效果。
package kill.window; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Scanner; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; public class KillServer { private Set<Integer> ports; public static void main(String[] args) throws InterruptedException { System.out.println("請輸入要殺掉的windows進程的端口號,如果有多個,則以逗號相隔"); System.out.println("Please input kill port"); Scanner scanner = new Scanner(System.in); String input = scanner.next(); scanner.close(); String[] split = input.split(","); Set<Integer> ports = new HashSet<>(); for (String spid : split) { try{ int pid = Integer.parseInt(spid); ports.add(pid); }catch(Exception e){ System.out.println("錯誤的端口號,請輸入一個或者多個端口,以英文逗號隔開"); try { Thread.sleep(5000); } catch (InterruptedException e1) { e1.printStackTrace(); } System.exit(0); } } KillServer kill = new KillServer(); kill.ports = ports; System.out.println("need kill " + ports.size() + " num"); for (Integer pid : ports) { kill.start(pid); } System.out.println("清理完畢,程序即將退出"); System.out.println("SUCCESS"); Thread.sleep(5000); System.exit(0); } public void start(int port){ Runtime runtime = Runtime.getRuntime(); try { //查找進程號 Process p = runtime.exec("cmd /c netstat -ano | findstr \""+port+"\""); InputStream inputStream = p.getInputStream(); List<String> read = read(inputStream, "UTF-8"); if(read.size() == 0){ System.out.println("找不到該端口的進程"); try { Thread.sleep(6000); System.exit(0); } catch (InterruptedException e) { e.printStackTrace(); } }else{ for (String string : read) { System.out.println(string); } System.out.println("找到"+read.size()+"個進程,正在准備清理"); kill(read); } } catch (IOException e) { e.printStackTrace(); } } /** * 驗證此行是否為指定的端口,因為 findstr命令會是把包含的找出來,例如查找80端口,但是會把8099查找出來 * @param str * @return */ private boolean validPort(String str){ Pattern pattern = Pattern.compile("^ *[a-zA-Z]+ +\\S+"); Matcher matcher = pattern.matcher(str); matcher.find(); String find = matcher.group(); int spstart = find.lastIndexOf(":"); find = find.substring(spstart + 1); int port = 0; try { port = Integer.parseInt(find); } catch (NumberFormatException e) { System.out.println("查找到錯誤的端口:" + find); return false; } if(this.ports.contains(port)){ return true; }else{ return false; } } /** * 更換為一個Set,去掉重復的pid值 * @param data */ public void kill(List<String> data){ Set<Integer> pids = new HashSet<>(); for (String line : data) { int offset = line.lastIndexOf(" "); String spid = line.substring(offset); spid = spid.replaceAll(" ", ""); int pid = 0; try { pid = Integer.parseInt(spid); } catch (NumberFormatException e) { System.out.println("獲取的進程號錯誤:" + spid); } pids.add(pid); } killWithPid(pids); } /** * 一次性殺除所有的端口 * @param pids */ public void killWithPid(Set<Integer> pids){ for (Integer pid : pids) { try { Process process = Runtime.getRuntime().exec("taskkill /F /pid "+pid+""); InputStream inputStream = process.getInputStream(); String txt = readTxt(inputStream, "GBK"); System.out.println(txt); } catch (IOException e) { e.printStackTrace(); } } } private List<String> read(InputStream in,String charset) throws IOException{ List<String> data = new ArrayList<>(); BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset)); String line; while((line = reader.readLine()) != null){ boolean validPort = validPort(line); if(validPort){ data.add(line); } } reader.close(); return data; } public String readTxt(InputStream in,String charset) throws IOException{ BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset)); StringBuffer sb = new StringBuffer(); String line; while((line = reader.readLine()) != null){ sb.append(line); } reader.close(); return sb.toString(); } }
