端口冲突的解决方案
端口冲突通常发生在尝试运行两个或多个应用程序或服务时,它们尝试
使用同一个端口号
,导致系统无法正确分配资源。
各种端口错误
你是否遇到过下面这些报错信息呢?
-
Windows 系统报错:
markdown系统错误 1004 套接字操作尝试使用一个已由另一个进程或服务占用的端口。
-
Windows 系统命令提示符报错:
markdownThe requested address is not available.
-
Java 程序运行时报错:
markdownjava.net.BindException: Address already in use: local port 8080
-
Apache HTTP 服务器报错:
markdownAH00526: Syntax error on line 287: Could not bind to address 0.0.0.0:80 - Address already in use
-
Nginx 报错:
markdownlisten 80 failed (98: Address already in use)
-
MySQL 报错:
markdown[Warning] Failed to start slave; MySQL error: 1130 - Host 'host' is not allowed to connect to this MySQL server
-
Windows 服务管理器报错:
markdownThe service did not start due to a logon failure.
-
SpringBoot 工程启动报错:
markdownWeb 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
javaserver: port: 3000 #配置你的端口 sdk: port: retry-count: 10 #尝试重试次数 max-port: 10000 #最大端口数 min-port: 1000 #最小端口数
-
配置类
javaimport 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"); } }
-
运行结果
成功更换