在做服务一键更新时,发现了一个问题,关闭服务时,对应的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调用效果
linux调用效果
还没有评论,来说两句吧...