在ubuntu系统上,某个进程占用了9999端口,这个进程结束后,此端口还会被占用一段时间,新启动的进程无法使用。 我不想这样,我该怎么办?
eeeeeeeeeeeeeeeeeeeeeee
在 Ubuntu 上,如果一个进程占用了 9999 端口,并且进程结束后该端口仍然处于 TIME_WAIT 状态,导致新进程无法立即绑定,你可以采取以下方法解决:
方法 1:启用 SO_REUSEADDR
在你的程序代码中,设置 SO_REUSEADDR
选项,可以允许端口在 TIME_WAIT 状态下被立即复用。例如,在 Node.js 或其他网络编程环境中:
Node.js 示例
const net = require('net');
const server = net.createServer();
server.listen(9999, '0.0.0.0', () => {
console.log('Server started on port 9999');
}).on('error', (err) => {
console.error('Error:', err);
});
server.on('connection', (socket) => {
console.log('New connection established');
});
或者在 Python 的 socket
编程:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 允许端口复用
sock.bind(('0.0.0.0', 9999))
sock.listen(5)
while True:
conn, addr = sock.accept()
print(f"Connected by {addr}")
这种方式可以避免端口被 TIME_WAIT 状态占用的问题。
方法 2:手动释放端口
如果端口仍然被占用,你可以手动释放:
-
查看占用端口的进程
sudo lsof -i :9999
或者
sudo netstat -tulnp | grep 9999
-
强制杀死进程
sudo kill -9 <PID>
其中
<PID>
是占用端口的进程 ID。 -
查看 TIME_WAIT 状态
netstat -anp | grep 9999
-
强制回收 TIME_WAIT 状态的端口
sudo fuser -k 9999/tcp
方法 3:调整 Linux 内核参数
如果你希望全局性减少端口进入 TIME_WAIT 状态的时间,可以调整 Linux 内核参数:
-
降低 TIME_WAIT 端口的保留时间
sudo sysctl -w net.ipv4.tcp_fin_timeout=10
这个值默认为 60,表示 60 秒后才会释放 TIME_WAIT 状态。
-
允许 TIME_WAIT 端口快速复用
sudo sysctl -w net.ipv4.tcp_tw_reuse=1 sudo sysctl -w net.ipv4.tcp_tw_recycle=1
⚠️注意:
tcp_tw_recycle
在 Linux 4.12 以后已被移除,若你的系统是较新版本,可以使用tcp_tw_reuse=1
代替。 -
永久生效
你可以将这些参数写入/etc/sysctl.conf
:echo "net.ipv4.tcp_fin_timeout=10" | sudo tee -a /etc/sysctl.conf echo "net.ipv4.tcp_tw_reuse=1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p
方法 4:使用 SO_LINGER
立即释放端口
在某些编程环境(如 C/C++),你可以使用 SO_LINGER
选项,使得进程关闭后端口立即释放:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
listen(sockfd, 5);
printf("Listening on port 9999...\n");
while (1) {
int client_fd = accept(sockfd, NULL, NULL);
if (client_fd >= 0) {
printf("New connection accepted\n");
close(client_fd);
}
}
close(sockfd);
return 0;
}
这个选项 SO_LINGER
可以在 close()
之后立即释放端口,而不是进入 TIME_WAIT
。
总结
方法 | 适用场景 | 是否推荐 |
---|---|---|
启用 SO_REUSEADDR |
代码可修改,避免 TIME_WAIT | ✅ 推荐 |
手动释放端口 | 临时解决占用问题 | ⚠️ 需手动操作 |
调整内核参数 | 影响全局 TCP 端口释放策略 | ⚠️ 影响整个系统 |
使用 SO_LINGER |
C 语言等底层编程 | ✅ 推荐(仅适用于 C/C++) |
最佳做法
- 代码层面:使用
SO_REUSEADDR
- 系统优化:调整
tcp_fin_timeout
- 紧急情况:手动释放端口 (
fuser -k 9999/tcp
)
这样,你就可以避免端口长时间被 TIME_WAIT 占用的问题。🚀
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
2021-02-10 使用mysql命令行工具登录mycat报错:ERROR 1045 (HY000): Access denied for user 'mycat', because password is error
2021-02-10 远程连接mongodb,Connection refused的解决办法