使用java代码关闭指定端口的程序-windows
发布在极乐科技2016年11月15日view:3023BrettBat
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

欢迎关注极乐科技知乎专栏:极乐科技,前后端干货全推送!


来源:使用java代码关闭指定端口的程序-windows 作者:朱小杰

  • 一:问题由史
  • 二:基础知识
    • 2.1、java要怎么实现
    • 2.2、根据端口查找进程
    • 2.3、根据进程号删除进程
  • 三:java实现,支持一次性杀死多个端口

一:问题由史

今天遇到一个问题,就是在实现自动化灾备的时候,发现原有死掉的程序没有完全关闭,当然这都不是本文的重点,重点是这个时候,我得把它完全关闭,所以才有了这篇文章。

二:基础知识

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可以执行操作系统的脚本,不论是什么操作,系统,那么我们就可以用这个方法,来直接执行这些命令来达到相应的效果。

作者:极乐君

链接:https://zhuanlan.zhihu.com/p/23675448 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

亲测有效!!!

评论
发表评论
暂无评论
WRITTEN BY
PUBLISHED IN
极乐科技

面向IT技术人员和技术供应商服务的平台网站,我们的口号是:让技术变得更简单! 极乐网

友情链接 大搜车前端团队博客
我的收藏