java 关闭指定端口 兼容windows和linux

原创  郑建华   2021-08-21   76人阅读  0 条评论

    在做服务一键更新时,发现了一个问题,关闭服务时,对应的webSocket端口没有关掉,导致服务重启不成功,所以需要在关闭服务时调用方法,关闭webSocket端口,为了彻底关掉端口,可以通过命令将其kill掉,那如何通过java来实现呢。

    说到命令,就要区分操作系统,windows和liunx的命令还是不一样的。

    windows下:

    查询端口占用命令:netstat -ano | findstr 端口号

    关闭端口命令: taskkill /F /pid pid的值

    linux下:

    查询端口占用命令:netstat -tunlp |grep 端口号

    关闭端口命令:kill -9 pid的值

    

    java实现

    1、可以通过Runtim r=Runtime.getRuntime(); r.exec('命令内容');来实现执行命令功能,此功能在windows系统,linux系统均可运行,但是在服务器上,windows环境下会有权限问题。

    2、windows模式下,可以使用jPowerShell工具包,调用PowerShell session = PowerShell.openSession();PowerShellResponse powerShellResponse = session.executeCommand('命令内容'); powerShell在linux下没有默认支持,需要安装。


    代码:

<dependency>
    <groupId>com.profesorfalken</groupId>
    <artifactId>jPowerShell</artifactId>
    <version>3.1.1</version>
</dependency>
import com.profesorfalken.jpowershell.PowerShell;
import com.profesorfalken.jpowershell.PowerShellResponse;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName KillPortUtils
 * @Description KillPortUtils 关闭端口
 * @Author zhengjianhua
 * @Date 2021/8/20 11:06
 * @Version 1.0
 */
public class KillPortUtils {
    /** 日志 */
    private static final Log logger = LogFactory.getLog(KillPortUtils.class);

    // 开始方法
    public static void start(int port) throws IOException {
        Set<Integer> ports = new HashSet<>();
        // 将要关闭的端口添加到set中
        ports.add(port);
        // 判断linux环境
        Boolean isLinux = isOSLinux();
        // 查询端口命令 linux 与 windows区分
        String command = isLinux ? "netstat -tunlp |grep " + port : "cmd /c netstat -ano | findstr " + port;
        logger.error("执行命令:" + command);
        // 读取内容
        List<String> read = execAndRead(command, isLinux, ports);
        if (read.size() == 0) {
            logger.error("未查询到端口被占用");
            return;
        } else {
            // 关闭端口
            kill(read, isLinux);
        }
    }

    // 执行命令并且读取结果
    private static List<String> execAndRead(String command, Boolean isLinux, Set<Integer> ports) throws IOException {
        // 读取结果
        List<String> read = new ArrayList<String>();
        if (!isLinux) {
            PowerShell session = PowerShell.openSession();
            PowerShellResponse powerShellResponse = session.executeCommand(command);
            String outPut = powerShellResponse.getCommandOutput();
            if (StringUtils.isBlank(outPut)) {
                logger.error("未查询到端口被占用");
                session.close();
                return read;
            }
            // 获取换行符
            String lineSeparator = System.lineSeparator();
            // 换行
            String[] lineArray = outPut.split(lineSeparator);
            if (lineArray != null && lineArray.length > 0) {
                for (int i = 0; i < lineArray.length; i++) {
                    String line = lineArray[i];
                    // 验证端口
                    boolean validPort = validPort(line, isLinux, ports);
                    if (validPort) {
                        // 添加内容
                        read.add(line);
                    }
                }
            }
            session.close();
        } else {
            Runtime runtime = Runtime.getRuntime();
            //查找进程号
            Process p = runtime.exec(command);
            InputStream inputStream = p.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    // 验证端口
                    boolean validPort = validPort(line, isLinux, ports);
                    if (validPort) {
                        // 添加内容
                        read.add(line);
                    }
                }
                inputStream.close();
                reader.close();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            } finally {
                inputStream.close();
                reader.close();
            }
        }
        return read;
    }

    /**
     * 验证此行是否为指定的端口,因为 findstr命令会是把包含的找出来,例如查找80端口,但是会把8099查找出来
     *
     * @param str
     * @return
     */
    private static boolean validPort(String str, Boolean isLinux, Set<Integer> ports) {
        String find = "";
        // linux TCP    0.0.0.0:12349          0.0.0.0:0              LISTENING       30700
        // windows tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      2319/python
        String reg = isLinux ? ":[0-9]+" : "^ *[a-zA-Z]+ +\\S+";
        // 匹配正则
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(str);
        Boolean findFlag = matcher.find();
        logger.error("读取数据:" + str);
        // 未匹配到则直接返回
        if (!findFlag) {
            return false;
        }
        // 获取匹配内容
        find = matcher.group();
        // 处理数据
        int spstart = find.lastIndexOf(":");
        // 截取掉冒号
        find = find.substring(spstart + 1);
        int port = 0;
        try {
            port = Integer.parseInt(find);
        } catch (NumberFormatException e) {
            return false;
        }
        // 端口在其中 则通过验证
        return ports.contains(port);
    }

    /**
     * 更换为一个Set,去掉重复的pid值
     *
     * @param data
     */
    private static void kill(List<String> data, Boolean isLinux) throws IOException {
        // linux TCP    0.0.0.0:12349          0.0.0.0:0              LISTENING       30700
        // windows tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN      2319/python
        Set<Integer> pids = new HashSet<>();
        for (String line : data) {
            // 去除前后空格
            line = line.trim();
            // 获取最后一个空格下标
            int offset = line.lastIndexOf(" ");
            // 截取最后的内容 如 30700 或者 2319/python
            String spid = line.substring(offset);
            // 替换其中的空格
            spid = spid.replaceAll(" ", "");
            // 如果存在/
            int lastSlashIndex = spid.lastIndexOf("/");
            if (lastSlashIndex != -1) {
                // 处理/
                spid = spid.substring(0, lastSlashIndex);
            }
            try {
                int pid = 0;
                pid = Integer.parseInt(spid);
                pids.add(pid);
            } catch (NumberFormatException e) {
                logger.error(e.getMessage(), e);
            }
        }
        logger.error("需要关闭的pid:" + pids);
        if (CollectionUtils.isNotEmpty(pids)) {
            killWithPid(pids, isLinux);
        }
    }

    /**
     * 一次性杀除所有的端口
     *
     * @param pids
     */
    private static void killWithPid(Set<Integer> pids, Boolean isLinux) throws IOException {
        if (isLinux) {
            for (Integer pid : pids) {
                String commond = "kill -9 " + pid;
                logger.error("关闭端口命令:" + commond);
                Process process = Runtime.getRuntime().exec(commond);
                InputStream inputStream = process.getInputStream();
                String txt = readTxt(inputStream, "GBK");
                logger.error("关闭端口结果:" + txt);
            }
        } else {
            PowerShell session = PowerShell.openSession();
            for (Integer pid : pids) {
                String commond = "taskkill /F /pid " + pid;
                logger.error("关闭端口命令:" + commond);
                PowerShellResponse powerShellResponse = session.executeCommand(commond);
                String outPut = powerShellResponse.getCommandOutput();
                logger.error("关闭端口结果:" + outPut);
            }
            session.close();
        }
    }


    private static List<String> read(String outPut, Boolean isLinux, Set<Integer> ports) throws IOException {
        List<String> data = new ArrayList<>();
        // 获取换行符
        String lineSeparator = System.lineSeparator();
        // 换行
        String[] lineArray = outPut.split(lineSeparator);
        if (lineArray != null && lineArray.length > 0) {
            for (int i = 0; i < lineArray.length; i++) {
                String line = lineArray[i];
                // 验证端口
                boolean validPort = validPort(line, isLinux, ports);
                if (validPort) {
                    // 添加内容
                    data.add(line);
                }
            }
        }
        return data;
    }


    private static boolean isOSLinux() {
        Properties prop = System.getProperties();
        String os = prop.getProperty("os.name");
        return os != null && os.toLowerCase().indexOf("linux") > -1;
    }

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

}

通过KillPortUtils.start(9099);调用即可


windows调用效果

image.png

linux调用效果

image.png


本文地址:https://www.zjh336.cn/?id=2055
版权声明:本文为原创文章,版权归 郑建华 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?