端口冲突的解决方案以及SpringBoot自动检测可用端口demo

端口冲突的解决方案

端口冲突通常发生在尝试运行两个或多个应用程序或服务时,它们尝试使用同一个端口号,导致系统无法正确分配资源。

各种端口错误

你是否遇到过下面这些报错信息呢?

  1. Windows 系统报错:

    markdown 复制代码
    系统错误 1004 
    套接字操作尝试使用一个已由另一个进程或服务占用的端口。
  2. Windows 系统命令提示符报错:

    markdown 复制代码
    The requested address is not available.
  3. Java 程序运行时报错:

    markdown 复制代码
    java.net.BindException: Address already in use: local port 8080
  4. Apache HTTP 服务器报错:

    markdown 复制代码
    AH00526: Syntax error on line 287: Could not bind to address 0.0.0.0:80 - Address already in use
  5. Nginx 报错:

    markdown 复制代码
    listen 80 failed (98: Address already in use)
  6. MySQL 报错:

    markdown 复制代码
    [Warning] Failed to start slave; MySQL error: 1130 - Host 'host' is not allowed to connect to this MySQL server
  7. Windows 服务管理器报错:

    markdown 复制代码
    The service did not start due to a logon failure.
  8. SpringBoot 工程启动报错:

    markdown 复制代码
    Web server failed to start. Port 8080 was already in use.

解决方案

1.Windows

  • **查看占用端口的PID

    shell 复制代码
    #假设我现在3000端口被占用
    netstat -ano | findstr 3000
    # 得到最后一个就是PID,也就是`18576`
    TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       18576
  • 查询运行程序

    shell 复制代码
    #根据PID,也就是上面得到的`18576`
    tasklist | findstr 18576
    # 得到第一个就是应用程序名,也就是`node.exe`
    node.exe                     18576 Console                   10    147,444 K

    如果此时你认识这个应用,并且它可以关闭,直接进入最后杀死进程阶段,如果你不确定,继续下一步

  • 查询程序路径

    shell 复制代码
    #根据应用名,也就是上面得到的`node.exe`
    wmic process where name="node.exe" get processid,executablepath
    # 得到第一个就是应用程序路径,第二个就是就是`PID`
    D:\Downloads\nodejs\node.exe  18576
  • 命令杀死进程

    shell 复制代码
    #根据PID,也就是上面得到的`18576`
    taskkill -PID 18576 -F
  • 任务管理器杀死进程

2. Linux

shell 复制代码
# 查端口
sudo lsof -i :80
# 根据PID查程序名和路径
ps -ef | grep 1037
#杀死进程
kill -9 $PID

3. SpringBoot解决

在你的配置文件中

yml 复制代码
server
  port: 随便一个端口
  • 有没有可能让springboot自己检查端口是否别占用呢?并且给我们更换到可用端口呢?

    当然实际不要怎么做,上线后端口需要固定,这只是一个锻炼思维的一个demo

  • maven导包

    xml 复制代码
    <parent>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-parent</artifactId>
    	<version>2.7.12</version>
    	<relativePath/>
     </parent>
    
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version> <!-- 使用最新版或适合你项目的版本 -->
            <scope>provided</scope> <!-- 在编译时添加,运行时不需要 -->
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version> <!-- 使用最新版或适合你项目的版本 -->
        </dependency>
    </dependencies>
  • application.yml

    java 复制代码
    server:
      port: 3000 #配置你的端口
    sdk:
      port:
        retry-count: 10 #尝试重试次数
        max-port: 10000 #最大端口数
        min-port: 1000 #最小端口数
  • 配置类

    java 复制代码
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.util.Random;
    
    /**
     * @ Author:Yang
     * @ Description:自动加载可用端口配置
     * @ create:2024-10-06-13:54
     */
    
    @Slf4j
    @Configuration
    public class PortAutoConfiguration {
        @Value("${server.port:8080}")
        private int defaultPort;
    
        @Value("${sdk.port.retry-count:10}")
        private int retryCount;
    
        @Value("${sdk.port.max-port:100000}")
        private int maxPort;
    
        @Value("${sdk.port.min-port:1000}")
        private int minPort;
    
        @Bean
        public TomcatConnectorCustomizer customServerPortTomcatConnectorCustomizer() {
        	// 尝试次数为0,则设置为0
            if (retryCount < 0) retryCount = 0;
    		// 确保最大端口不小于最小端口
            if (maxPort < minPort) maxPort = minPort;
    		
    		// 从默认端口开始寻找可用端口
            int port = findAvailablePort(defaultPort);
    
            log.info("设置端口为 port : {}", port);
    		
    		// 返回可用端口
            return connector -> connector.setPort(port);
        }
    
    
        private int findAvailablePort(int port) {
            Random random = new Random();
            //已经尝试次数
            int count = 0;
            // 这样可以保证最小为 1 ,random的最小为0
            int bound = maxPort - minPort + 1;
    
            while (count < retryCount) {
                try (ServerSocket serverSocket = new ServerSocket(port)) {
                    return port;
                } catch (IOException e) {
                    // 端口被占用,尝试下一个端口
                    int oldPort = port;
                    count++;
                    port = minPort + random.nextInt(bound);
                    log.warn("{}端口冲突,更换端口为{},已尝试{}次",oldPort,port,count);
                }
            }
    
            // 如果循环结束后仍未找到可用端口,抛出异常或返回特定值
            throw new RuntimeException("Unable to find an available port after " + retryCount + " retries");
        }
    }
  • 运行结果

    成功更换

相关推荐
源代码•宸8 分钟前
大厂技术岗面试之谈薪资
经验分享·后端·面试·职场和发展·golang·大厂·职级水平的薪资
Anastasiozzzz17 分钟前
Java Lambda 揭秘:从匿名内部类到底层原理的深度解析
java·开发语言
骇客野人19 分钟前
通过脚本推送Docker镜像
java·docker·容器
韩立学长35 分钟前
基于Springboot泉州旅游攻略平台d5h5zz02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·旅游
铁蛋AI编程实战36 分钟前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
晚霞的不甘1 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
SunnyDays10111 小时前
使用 Java 冻结 Excel 行和列:完整指南
java·冻结excel行和列
喵叔哟1 小时前
06-ASPNETCore-WebAPI开发
服务器·后端·c#
摇滚侠1 小时前
在 SpringBoot 项目中,开发工具使用 IDEA,.idea 目录下的文件需要提交吗
java·spring boot·intellij-idea
云姜.1 小时前
java多态
java·开发语言·c++