在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');
});

或者在 Pythonsocket 编程:

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:手动释放端口

如果端口仍然被占用,你可以手动释放:

  1. 查看占用端口的进程

    sudo lsof -i :9999
    

    或者

    sudo netstat -tulnp | grep 9999
    
  2. 强制杀死进程

    sudo kill -9 <PID>
    

    其中 <PID> 是占用端口的进程 ID。

  3. 查看 TIME_WAIT 状态

    netstat -anp | grep 9999
    
  4. 强制回收 TIME_WAIT 状态的端口

    sudo fuser -k 9999/tcp
    

方法 3:调整 Linux 内核参数

如果你希望全局性减少端口进入 TIME_WAIT 状态的时间,可以调整 Linux 内核参数:

  1. 降低 TIME_WAIT 端口的保留时间

    sudo sysctl -w net.ipv4.tcp_fin_timeout=10
    

    这个值默认为 60,表示 60 秒后才会释放 TIME_WAIT 状态。

  2. 允许 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 代替。

  3. 永久生效
    你可以将这些参数写入 /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 占用的问题。🚀

posted on   及途又八  阅读(36)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 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的解决办法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示